| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| example.js | 100% | (83 / 83) | 100% | (73 / 73) | 100% | (12 / 12) | 100% | (83 / 83) | |
| lib.npmtest_stylelint.js | 100% | (16 / 16) | 100% | (14 / 14) | 100% | (3 / 3) | 100% | (16 / 16) | |
| test.js | 100% | (54 / 54) | 100% | (39 / 39) | 100% | (13 / 13) | 100% | (54 / 54) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | 2 2 2 2 2 2 2 1 2 2 2 2 1 2 2 2 2 2 1 2 1 1 1 1 1 1 1 1 1 2 1 1 1 1 2 2 3 3 3 3 1 3 3 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 6 6 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | /*
example.js
quickstart example
instruction
1. save this script as example.js
2. run the shell command:
$ npm install npmtest-stylelint && PORT=8081 node example.js
3. play with the browser-demo on http://127.0.0.1:8081
*/
/* istanbul instrument in package npmtest_stylelint */
/*jslint
bitwise: true,
browser: true,
maxerr: 8,
maxlen: 96,
node: true,
nomen: true,
regexp: true,
stupid: true
*/
(function () {
'use strict';
var local;
// run shared js-env code - pre-init
(function () {
// init local
local = {};
// init modeJs
local.modeJs = (function () {
try {
return typeof navigator.userAgent === 'string' &&
typeof document.querySelector('body') === 'object' &&
typeof XMLHttpRequest.prototype.open === 'function' &&
'browser';
} catch (errorCaughtBrowser) {
return module.exports &&
typeof process.versions.node === 'string' &&
typeof require('http').createServer === 'function' &&
'node';
}
}());
// init global
local.global = local.modeJs === 'browser'
? window
: global;
// init utility2_rollup
local = local.global.utility2_rollup || (local.modeJs === 'browser'
? local.global.utility2_npmtest_stylelint
: global.utility2_moduleExports);
// export local
local.global.local = local;
}());
switch (local.modeJs) {
// post-init
// run browser js-env code - post-init
/* istanbul ignore next */
case 'browser':
local.testRunBrowser = function (event) {
Eif (!event || (event &&
event.currentTarget &&
event.currentTarget.className &&
event.currentTarget.className.includes &&
event.currentTarget.className.includes('onreset'))) {
// reset output
Array.from(
document.querySelectorAll('body > .resettable')
).forEach(function (element) {
switch (element.tagName) {
case 'INPUT':
case 'TEXTAREA':
element.value = '';
break;
default:
element.textContent = '';
}
});
}
switch (event && event.currentTarget && event.currentTarget.id) {
case 'testRunButton1':
// show tests
Eif (document.querySelector('#testReportDiv1').style.display === 'none') {
document.querySelector('#testReportDiv1').style.display = 'block';
document.querySelector('#testRunButton1').textContent =
'hide internal test';
local.modeTest = true;
local.testRunDefault(local);
// hide tests
} else {
document.querySelector('#testReportDiv1').style.display = 'none';
document.querySelector('#testRunButton1').textContent = 'run internal test';
}
break;
// custom-case
default:
break;
}
Iif (document.querySelector('#inputTextareaEval1') && (!event || (event &&
event.currentTarget &&
event.currentTarget.className &&
event.currentTarget.className.includes &&
event.currentTarget.className.includes('oneval')))) {
// try to eval input-code
try {
/*jslint evil: true*/
eval(document.querySelector('#inputTextareaEval1').value);
} catch (errorCaught) {
console.error(errorCaught);
}
}
};
// log stderr and stdout to #outputTextareaStdout1
['error', 'log'].forEach(function (key) {
console[key + '_original'] = console[key];
console[key] = function () {
var element;
console[key + '_original'].apply(console, arguments);
element = document.querySelector('#outputTextareaStdout1');
Iif (!element) {
return;
}
// append text to #outputTextareaStdout1
element.value += Array.from(arguments).map(function (arg) {
return typeof arg === 'string'
? arg
: JSON.stringify(arg, null, 4);
}).join(' ') + '\n';
// scroll textarea to bottom
element.scrollTop = element.scrollHeight;
};
});
// init event-handling
['change', 'click', 'keyup'].forEach(function (event) {
Array.from(document.querySelectorAll('.on' + event)).forEach(function (element) {
element.addEventListener(event, local.testRunBrowser);
});
});
// run tests
local.testRunBrowser();
break;
// run node js-env code - post-init
/* istanbul ignore next */
case 'node':
// export local
module.exports = local;
// require modules
local.fs = require('fs');
local.http = require('http');
local.url = require('url');
// init assets
local.assetsDict = local.assetsDict || {};
/* jslint-ignore-begin */
local.assetsDict['/assets.index.template.html'] = '\
<!doctype html>\n\
<html lang="en">\n\
<head>\n\
<meta charset="UTF-8">\n\
<meta name="viewport" content="width=device-width, initial-scale=1">\n\
<title>{{env.npm_package_name}} (v{{env.npm_package_version}})</title>\n\
<style>\n\
/*csslint\n\
box-sizing: false,\n\
universal-selector: false\n\
*/\n\
* {\n\
box-sizing: border-box;\n\
}\n\
body {\n\
background: #dde;\n\
font-family: Arial, Helvetica, sans-serif;\n\
margin: 2rem;\n\
}\n\
body > * {\n\
margin-bottom: 1rem;\n\
}\n\
.utility2FooterDiv {\n\
margin-top: 20px;\n\
text-align: center;\n\
}\n\
</style>\n\
<style>\n\
/*csslint\n\
*/\n\
textarea {\n\
font-family: monospace;\n\
height: 10rem;\n\
width: 100%;\n\
}\n\
textarea[readonly] {\n\
background: #ddd;\n\
}\n\
</style>\n\
</head>\n\
<body>\n\
<!-- utility2-comment\n\
<div id="ajaxProgressDiv1" style="background: #d00; height: 2px; left: 0; margin: 0; padding: 0; position: fixed; top: 0; transition: background 0.5s, width 1.5s; width: 25%;"></div>\n\
utility2-comment -->\n\
<h1>\n\
<!-- utility2-comment\n\
<a\n\
{{#if env.npm_package_homepage}}\n\
href="{{env.npm_package_homepage}}"\n\
{{/if env.npm_package_homepage}}\n\
target="_blank"\n\
>\n\
utility2-comment -->\n\
{{env.npm_package_name}} (v{{env.npm_package_version}})\n\
<!-- utility2-comment\n\
</a>\n\
utility2-comment -->\n\
</h1>\n\
<h3>{{env.npm_package_description}}</h3>\n\
<!-- utility2-comment\n\
<h4><a download href="assets.app.js">download standalone app</a></h4>\n\
<button class="onclick onreset" id="testRunButton1">run internal test</button><br>\n\
<div id="testReportDiv1" style="display: none;"></div>\n\
utility2-comment -->\n\
\n\
\n\
\n\
<label>stderr and stdout</label>\n\
<textarea class="resettable" id="outputTextareaStdout1" readonly></textarea>\n\
<!-- utility2-comment\n\
{{#if isRollup}}\n\
<script src="assets.app.js"></script>\n\
{{#unless isRollup}}\n\
utility2-comment -->\n\
<script src="assets.utility2.rollup.js"></script>\n\
<script src="jsonp.utility2._stateInit?callback=window.utility2._stateInit"></script>\n\
<script src="assets.npmtest_stylelint.rollup.js"></script>\n\
<script src="assets.example.js"></script>\n\
<script src="assets.test.js"></script>\n\
<!-- utility2-comment\n\
{{/if isRollup}}\n\
utility2-comment -->\n\
<div class="utility2FooterDiv">\n\
[ this app was created with\n\
<a href="https://github.com/kaizhu256/node-utility2" target="_blank">utility2</a>\n\
]\n\
</div>\n\
</body>\n\
</html>\n\
';
/* jslint-ignore-end */
Iif (local.templateRender) {
local.assetsDict['/'] = local.templateRender(
local.assetsDict['/assets.index.template.html'],
{
env: local.objectSetDefault(local.env, {
npm_package_description: 'the greatest app in the world!',
npm_package_name: 'my-app',
npm_package_nameAlias: 'my_app',
npm_package_version: '0.0.1'
})
}
);
} else {
local.assetsDict['/'] = local.assetsDict['/assets.index.template.html']
.replace((/\{\{env\.(\w+?)\}\}/g), function (match0, match1) {
// jslint-hack
String(match0);
switch (match1) {
case 'npm_package_description':
return 'the greatest app in the world!';
case 'npm_package_name':
return 'my-app';
case 'npm_package_nameAlias':
return 'my_app';
case 'npm_package_version':
return '0.0.1';
}
});
}
// run the cli
Eif (local.global.utility2_rollup || module !== require.main) {
break;
}
local.assetsDict['/assets.example.js'] =
local.assetsDict['/assets.example.js'] ||
local.fs.readFileSync(__filename, 'utf8');
// bug-workaround - long $npm_package_buildCustomOrg
/* jslint-ignore-begin */
local.assetsDict['/assets.npmtest_stylelint.rollup.js'] =
local.assetsDict['/assets.npmtest_stylelint.rollup.js'] ||
local.fs.readFileSync(
local.npmtest_stylelint.__dirname + '/lib.npmtest_stylelint.js',
'utf8'
).replace((/^#!/), '//');
/* jslint-ignore-end */
local.assetsDict['/favicon.ico'] = local.assetsDict['/favicon.ico'] || '';
// if $npm_config_timeout_exit exists,
// then exit this process after $npm_config_timeout_exit ms
if (Number(process.env.npm_config_timeout_exit)) {
setTimeout(process.exit, Number(process.env.npm_config_timeout_exit));
}
// start server
if (local.global.utility2_serverHttp1) {
break;
}
process.env.PORT = process.env.PORT || '8081';
console.error('server starting on port ' + process.env.PORT);
local.http.createServer(function (request, response) {
request.urlParsed = local.url.parse(request.url);
if (local.assetsDict[request.urlParsed.pathname] !== undefined) {
response.end(local.assetsDict[request.urlParsed.pathname]);
return;
}
response.statusCode = 404;
response.end();
}).listen(process.env.PORT);
break;
}
}());
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 2 2 2 2 2 2 2 1 2 2 2 2 1 1 1 1 | /* istanbul instrument in package npmtest_stylelint */
/*jslint
bitwise: true,
browser: true,
maxerr: 8,
maxlen: 96,
node: true,
nomen: true,
regexp: true,
stupid: true
*/
(function () {
'use strict';
var local;
// run shared js-env code - pre-init
(function () {
// init local
local = {};
// init modeJs
local.modeJs = (function () {
try {
return typeof navigator.userAgent === 'string' &&
typeof document.querySelector('body') === 'object' &&
typeof XMLHttpRequest.prototype.open === 'function' &&
'browser';
} catch (errorCaughtBrowser) {
return module.exports &&
typeof process.versions.node === 'string' &&
typeof require('http').createServer === 'function' &&
'node';
}
}());
// init global
local.global = local.modeJs === 'browser'
? window
: global;
// init utility2_rollup
local = local.global.utility2_rollup || local;
// init lib
local.local = local.npmtest_stylelint = local;
// init exports
if (local.modeJs === 'browser') {
local.global.utility2_npmtest_stylelint = local;
} else {
module.exports = local;
module.exports.__dirname = __dirname;
module.exports.module = module;
}
}());
}());
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | 2 2 2 2 2 2 2 1 2 2 1 1 1 1 2 2 2 2 1 1 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 1 2 2 1 2 2 1 2 2 1 1 1 1 1 | /* istanbul instrument in package npmtest_stylelint */
/*jslint
bitwise: true,
browser: true,
maxerr: 8,
maxlen: 96,
node: true,
nomen: true,
regexp: true,
stupid: true
*/
(function () {
'use strict';
var local;
// run shared js-env code - pre-init
(function () {
// init local
local = {};
// init modeJs
local.modeJs = (function () {
try {
return typeof navigator.userAgent === 'string' &&
typeof document.querySelector('body') === 'object' &&
typeof XMLHttpRequest.prototype.open === 'function' &&
'browser';
} catch (errorCaughtBrowser) {
return module.exports &&
typeof process.versions.node === 'string' &&
typeof require('http').createServer === 'function' &&
'node';
}
}());
// init global
local.global = local.modeJs === 'browser'
? window
: global;
switch (local.modeJs) {
// re-init local from window.local
case 'browser':
local = local.global.utility2.objectSetDefault(
local.global.utility2_rollup || local.global.local,
local.global.utility2
);
break;
// re-init local from example.js
case 'node':
local = (local.global.utility2_rollup || require('utility2'))
.requireReadme();
break;
}
// export local
local.global.local = local;
}());
// run shared js-env code - function
(function () {
return;
}());
switch (local.modeJs) {
// run browser js-env code - function
case 'browser':
break;
// run node js-env code - function
case 'node':
break;
}
// run shared js-env code - post-init
(function () {
return;
}());
switch (local.modeJs) {
// run browser js-env code - post-init
case 'browser':
local.testCase_browser_nullCase = local.testCase_browser_nullCase || function (
options,
onError
) {
/*
* this function will test browsers's null-case handling-behavior-behavior
*/
onError(null, options);
};
// run tests
local.nop(local.modeTest &&
document.querySelector('#testRunButton1') &&
document.querySelector('#testRunButton1').click());
break;
// run node js-env code - post-init
/* istanbul ignore next */
case 'node':
local.testCase_buildApidoc_default = local.testCase_buildApidoc_default || function (
options,
onError
) {
/*
* this function will test buildApidoc's default handling-behavior-behavior
*/
options = { modulePathList: module.paths };
local.buildApidoc(options, onError);
};
local.testCase_buildApp_default = local.testCase_buildApp_default || function (
options,
onError
) {
/*
* this function will test buildApp's default handling-behavior-behavior
*/
local.testCase_buildReadme_default(options, local.onErrorThrow);
local.testCase_buildLib_default(options, local.onErrorThrow);
local.testCase_buildTest_default(options, local.onErrorThrow);
local.testCase_buildCustomOrg_default(options, local.onErrorThrow);
options = [];
local.buildApp(options, onError);
};
local.testCase_buildCustomOrg_default = local.testCase_buildCustomOrg_default ||
function (options, onError) {
/*
* this function will test buildCustomOrg's default handling-behavior
*/
options = {};
local.buildCustomOrg(options, onError);
};
local.testCase_buildLib_default = local.testCase_buildLib_default || function (
options,
onError
) {
/*
* this function will test buildLib's default handling-behavior
*/
options = {};
local.buildLib(options, onError);
};
local.testCase_buildReadme_default = local.testCase_buildReadme_default || function (
options,
onError
) {
/*
* this function will test buildReadme's default handling-behavior-behavior
*/
options = {};
local.buildReadme(options, onError);
};
local.testCase_buildTest_default = local.testCase_buildTest_default || function (
options,
onError
) {
/*
* this function will test buildTest's default handling-behavior
*/
options = {};
local.buildTest(options, onError);
};
local.testCase_webpage_default = local.testCase_webpage_default || function (
options,
onError
) {
/*
* this function will test webpage's default handling-behavior
*/
options = { modeCoverageMerge: true, url: local.serverLocalHost + '?modeTest=1' };
local.browserTest(options, onError);
};
// run test-server
local.testRunServer(local);
break;
}
}());
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| stylelint.js | 100% | (1 / 1) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (1 / 1) |
| 1 2 3 4 5 6 7 | 1 | //#!/usr/bin/env node
"use strict"
require("../lib/cli")
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| alwaysIgnoredGlobs.js | 100% | (2 / 2) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (2 / 2) | |
| assignDisabledRanges.js | 19.19% | (19 / 99) | 0% | (0 / 52) | 0% | (0 / 12) | 20.21% | (19 / 94) | |
| augmentConfig.js | 17.5% | (28 / 160) | 1.09% | (1 / 92) | 8.33% | (1 / 12) | 17.88% | (27 / 151) | |
| cli.js | 59.68% | (37 / 62) | 37.5% | (18 / 48) | 100% | (0 / 0) | 59.02% | (36 / 61) | |
| createPlugin.js | 50% | (1 / 2) | 100% | (0 / 0) | 0% | (0 / 1) | 50% | (1 / 2) | |
| createStylelint.js | 100% | (21 / 21) | 50% | (1 / 2) | 100% | (1 / 1) | 100% | (21 / 21) | |
| createStylelintResult.js | 10.53% | (2 / 19) | 0% | (0 / 8) | 0% | (0 / 1) | 10.53% | (2 / 19) | |
| dynamicRequire.js | 50% | (1 / 2) | 100% | (0 / 0) | 0% | (0 / 1) | 50% | (1 / 2) | |
| getConfigForFile.js | 61.9% | (13 / 21) | 50% | (6 / 12) | 100% | (1 / 1) | 63.16% | (12 / 19) | |
| getPostcssResult.js | 18.18% | (10 / 55) | 0% | (0 / 43) | 0% | (0 / 2) | 18.52% | (10 / 54) | |
| index.js | 100% | (20 / 20) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (20 / 20) | |
| isPathIgnored.js | 42.11% | (8 / 19) | 8.33% | (1 / 12) | 100% | (1 / 1) | 42.11% | (8 / 19) | |
| lintSource.js | 30.43% | (21 / 69) | 25.49% | (13 / 51) | 33.33% | (1 / 3) | 32.31% | (21 / 65) | |
| needlessDisables.js | 8.33% | (3 / 36) | 0% | (0 / 26) | 0% | (0 / 2) | 8.33% | (3 / 36) | |
| normalizeRuleSettings.js | 12.5% | (3 / 24) | 0% | (0 / 25) | 0% | (0 / 1) | 12.5% | (3 / 24) | |
| postcssPlugin.js | 38.46% | (5 / 13) | 0% | (0 / 10) | 0% | (0 / 1) | 38.46% | (5 / 13) | |
| standalone.js | 43.14% | (44 / 102) | 22.64% | (12 / 53) | 50% | (2 / 4) | 43.56% | (44 / 101) |
| 1 2 3 4 5 6 7 8 | 1 1 | /* @flow */ "use strict" const alwaysIgnoredGlobs/*: Array<string>*/ = [ "**/node_modules/**", "**/bower_components/**" ] module.exports = alwaysIgnoredGlobs |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | /* @flow */
"use strict"
const _ = require("lodash")
const COMMAND_PREFIX = "stylelint-"
const disableCommand = COMMAND_PREFIX + "disable"
const enableCommand = COMMAND_PREFIX + "enable"
const disableLineCommand = COMMAND_PREFIX + "disable-line"
const disableNextLineCommand = COMMAND_PREFIX + "disable-next-line"
const ALL_RULES = "all"
/*:: type disabledRangeObject = {
[ruleName: string]: Array<{
start: number,
end?: number,
}>
}*/
// Run it like a plugin ...
module.exports = function (
root/*: Object*/,
result/*: Object*/
)/*: postcss$result*/ {
result.stylelint = result.stylelint || {}
// Most of the functions below work via side effects mutating
// this object
const disabledRanges/*: disabledRangeObject*/ = {
all: [],
}
result.stylelint.disabledRanges = disabledRanges
root.walkComments(checkComment)
return result
function processDisableLineCommand(comment/*: postcss$comment*/) {
getCommandRules(disableLineCommand, comment.text).forEach(ruleName => {
disableLine(comment.source.start.line, ruleName, comment)
})
}
function processDisableNextLineCommand(comment/*: postcss$comment*/) {
getCommandRules(disableNextLineCommand, comment.text).forEach(ruleName => {
disableLine(comment.source.start.line + 1, ruleName, comment)
})
}
function disableLine(
line/*: number*/,
ruleName/*: string*/,
comment/*: postcss$comment*/
) {
if (ruleIsDisabled(ALL_RULES)) {
throw comment.error("All rules have already been disabled", { plugin: "stylelint" })
}
if (ruleIsDisabled(ruleName)) {
throw comment.error(`"${ruleName}" has already been disabled`, { plugin: "stylelint" })
}
if (ruleName === ALL_RULES) {
Object.keys(disabledRanges).forEach(disabledRuleName => {
startDisabledRange(line, disabledRuleName)
endDisabledRange(line, disabledRuleName)
})
} else {
startDisabledRange(line, ruleName)
endDisabledRange(line, ruleName)
}
}
function processDisableCommand(comment/*: postcss$comment*/) {
getCommandRules(disableCommand, comment.text).forEach(ruleToDisable => {
if (ruleToDisable === ALL_RULES) {
if (ruleIsDisabled(ALL_RULES)) {
throw comment.error("All rules have already been disabled", { plugin: "stylelint" })
}
Object.keys(disabledRanges).forEach(ruleName => {
startDisabledRange(comment.source.start.line, ruleName)
})
return
}
if (ruleIsDisabled(ruleToDisable)) {
throw comment.error(`"${ruleToDisable}" has already been disabled`, { plugin: "stylelint" })
}
startDisabledRange(comment.source.start.line, ruleToDisable)
})
}
function processEnableCommand(comment/*: postcss$comment*/) {
getCommandRules(enableCommand, comment.text).forEach(ruleToEnable => {
if (ruleToEnable === ALL_RULES) {
if (_.values(disabledRanges).every(ranges => _.isEmpty(ranges) || !!_.last(ranges.end))) {
throw comment.error("No rules have been disabled", { plugin: "stylelint" })
}
Object.keys(disabledRanges).forEach(ruleName => {
if (!_.get(_.last(disabledRanges[ruleName]), "end")) {
endDisabledRange(comment.source.end.line, ruleName)
}
})
return
}
if (ruleIsDisabled(ALL_RULES) && disabledRanges[ruleToEnable] === undefined) {
// Get a starting point from the where all rules were disabled
if (!disabledRanges[ruleToEnable]) {
disabledRanges[ruleToEnable] = _.cloneDeep(disabledRanges.all)
} else {
disabledRanges[ruleToEnable].push(_.clone(_.last(disabledRanges[ALL_RULES])))
}
endDisabledRange(comment.source.end.line, ruleToEnable)
return
}
if (ruleIsDisabled(ruleToEnable)) {
endDisabledRange(comment.source.end.line, ruleToEnable)
return
}
throw comment.error(`"${ruleToEnable}" has not been disabled`, { plugin: "stylelint" })
})
}
function checkComment(comment/*: postcss$comment*/) {
const text = comment.text
// Ignore comments that are not relevant commands
if (text.indexOf(COMMAND_PREFIX) !== 0) {
return result
}
if (text.indexOf(disableLineCommand) === 0) {
processDisableLineCommand(comment)
} else if (text.indexOf(disableNextLineCommand) === 0) {
processDisableNextLineCommand(comment)
} else if (text.indexOf(disableCommand) === 0) {
processDisableCommand(comment)
} else if (text.indexOf(enableCommand) === 0) {
processEnableCommand(comment)
}
}
function getCommandRules(
command/*: string*/,
fullText/*: string*/
)/*: Array<string>*/ {
const rules = _.compact(fullText.slice(command.length).split(",")).map(r => r.trim())
if (_.isEmpty(rules)) {
return [ALL_RULES]
}
return rules
}
function startDisabledRange(line/*: number*/, ruleName/*: string*/) {
const rangeObj = { start: line }
ensureRuleRanges(ruleName)
disabledRanges[ruleName].push(rangeObj)
}
function endDisabledRange(line/*: number*/, ruleName/*: string*/) {
const lastRangeForRule = _.last(disabledRanges[ruleName])
if (!lastRangeForRule) {
return
}
// Add an `end` prop to the last range of that rule
lastRangeForRule.end = line
}
function ensureRuleRanges(ruleName/*: string*/) {
if (!disabledRanges[ruleName]) {
disabledRanges[ruleName] = _.cloneDeep(disabledRanges.all)
}
}
function ruleIsDisabled(ruleName/*: string*/)/*: boolean*/ {
if (disabledRanges[ruleName] === undefined) return false
if (_.last(disabledRanges[ruleName]) === undefined) return false
if (_.get(_.last(disabledRanges[ruleName]), "end") === undefined) return true
return false
}
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 1 1 1 1 1 1 1 1 1 1 1 | /* @flow */
"use strict"
const configurationError = require("./utils/configurationError")
const getModulePath = require("./utils/getModulePath")
const _ = require("lodash")
const fs = require("fs")
const globjoin = require("globjoin")
const normalizeRuleSettings = require("./normalizeRuleSettings")
const path = require("path")
const rules = require("./rules")
const dynamicRequire = require("./dynamicRequire")
const DEFAULT_IGNORE_FILENAME = ".stylelintignore"
const FILE_NOT_FOUND_ERROR_CODE = "ENOENT"
// - Merges config and configOverrides
// - Makes all paths absolute
// - Merges extends
function augmentConfigBasic(
stylelint/*: stylelint$internalApi*/,
config/*: stylelint$config*/,
configDir/*: string*/,
allowOverrides/*:: ?: boolean*/
)/*: Promise<stylelint$config>*/ {
return Promise.resolve().then(() => {
if (!allowOverrides) return config
return _.merge(config, stylelint._options.configOverrides)
}).then(augmentedConfig => {
return extendConfig(stylelint, augmentedConfig, configDir)
}).then(augmentedConfig => {
return absolutizePaths(augmentedConfig, configDir)
})
}
// Extended configs need to be run through augmentConfigBasic
// but do not need the full treatment. Things like pluginFunctions
// will be resolved and added by the parent config.
function augmentConfigExtended(
stylelint/*: stylelint$internalApi*/,
cosmiconfigResultArg/*: ?{
config: stylelint$config,
filepath: string,
}*/
)/*: Promise<?{ config: stylelint$config, filepath: string }>*/ {
const cosmiconfigResult = cosmiconfigResultArg // Lock in for Flow
if (!cosmiconfigResult) return Promise.resolve(null)
const configDir = path.dirname(cosmiconfigResult.filepath || "")
const cleanedConfig = _.omit(cosmiconfigResult.config, "ignoreFiles")
return augmentConfigBasic(stylelint, cleanedConfig, configDir).then(augmentedConfig => {
return {
config: augmentedConfig,
filepath: cosmiconfigResult.filepath,
}
})
}
function augmentConfigFull(
stylelint/*: stylelint$internalApi*/,
cosmiconfigResultArg/*: ?{
config: stylelint$config,
filepath: string,
}*/
)/*: Promise<?{ config: stylelint$config, filepath: string }>*/ {
const cosmiconfigResult = cosmiconfigResultArg // Lock in for Flow
Eif (!cosmiconfigResult) return Promise.resolve(null)
const config = cosmiconfigResult.config,
filepath = cosmiconfigResult.filepath
const configDir = stylelint._options.configBasedir || path.dirname(filepath || "")
return augmentConfigBasic(stylelint, config, configDir, true).then(augmentedConfig => {
return addIgnorePatterns(stylelint, augmentedConfig)
}).then(augmentedConfig => {
return addPluginFunctions(augmentedConfig)
}).then(augmentedConfig => {
return addProcessorFunctions(augmentedConfig)
}).then(augmentedConfig => {
if (!augmentedConfig.rules) {
throw configurationError("No rules found within configuration. Have you provided a \"rules\" property?")
}
return normalizeAllRuleSettings(augmentedConfig)
}).then(augmentedConfig => {
return {
config: augmentedConfig,
filepath: cosmiconfigResult.filepath,
}
})
}
// Load a file ignore ignore patterns, if there is one;
// then add them to the config as an ignorePatterns property
function addIgnorePatterns(
stylelint/*: stylelint$internalApi*/,
config/*: stylelint$config*/
)/*: Promise<stylelint$config>*/ {
const ignoreFilePath = stylelint._options.ignorePath || DEFAULT_IGNORE_FILENAME
const absoluteIgnoreFilePath = path.isAbsolute(ignoreFilePath) ? ignoreFilePath : path.resolve(process.cwd(), ignoreFilePath)
return new Promise((resolve, reject) => {
fs.readFile(absoluteIgnoreFilePath, "utf8", (err, data) => {
if (err) {
// If the file's not found, fine, we'll just
// consider it an empty array of globs
if (err.code === FILE_NOT_FOUND_ERROR_CODE) {
return resolve(config)
}
return reject(err)
}
// Add an ignorePatterns property to the config, containing the
// .gitignore-patterned globs loaded from .stylelintignore
const augmentedConfig/*: stylelint$config*/ = Object.assign({}, config, {
ignorePatterns: data,
})
resolve(augmentedConfig)
})
})
}
// Make all paths in the config absolute:
// - ignoreFiles
// - plugins
// - processors
// (extends handled elsewhere)
function absolutizePaths(
config/*: stylelint$config*/,
configDir/*: string*/
)/*: stylelint$config*/ {
if (config.ignoreFiles) {
config.ignoreFiles = [].concat(config.ignoreFiles).map(glob => {
if (path.isAbsolute(glob.replace(/^!/, ""))) return glob
return globjoin(configDir, glob)
})
}
if (config.plugins) {
config.plugins = [].concat(config.plugins).map(lookup => {
return getModulePath(configDir, lookup)
})
}
if (config.processors) {
config.processors = absolutizeProcessors(config.processors, configDir)
}
return config
}
// Processors are absolutized in their own way because
// they can be and return a string or an array
function absolutizeProcessors(
processors/*: stylelint$configProcessors*/,
configDir/*: string*/
)/*: stylelint$configProcessors*/ {
const normalizedProcessors = Array.isArray(processors) ? processors : [processors]
return normalizedProcessors.map(item => {
if (typeof item === "string") {
return getModulePath(configDir, item)
}
return [ getModulePath(configDir, item[0]), item[1] ]
})
}
function extendConfig(
stylelint/*: stylelint$internalApi*/,
config/*: stylelint$config*/,
configDir/*: string*/
)/*: Promise<stylelint$config>*/ {
if (config.extends === undefined) return Promise.resolve(config)
const normalizedExtends = Array.isArray(config.extends) ? config.extends : [config.extends]
const originalWithoutExtends = _.omit(config, "extends")
const loadExtends = normalizedExtends.reduce((resultPromise, extendLookup) => {
return resultPromise.then(resultConfig => {
return loadExtendedConfig(stylelint, resultConfig, configDir, extendLookup).then(extendResult => {
if (!extendResult) return resultConfig
return mergeConfigs(resultConfig, extendResult.config)
})
})
}, Promise.resolve(originalWithoutExtends))
return loadExtends.then(resultConfig => {
return mergeConfigs(resultConfig, originalWithoutExtends)
})
}
function loadExtendedConfig(
stylelint/*: stylelint$internalApi*/,
config/*: stylelint$config*/,
configDir/*: string*/,
extendLookup/*: string*/
)/*: Promise<?{ config: stylelint$config, filepath: string }>*/ {
const extendPath = getModulePath(configDir, extendLookup)
return stylelint._extendExplorer.load(null, extendPath)
}
// When merging configs (via extends)
// - plugin and processor arrays are joined
// - rules are merged via Object.assign, so there is no attempt made to
// merge any given rule's settings. If b contains the same rule as a,
// b's rule settings will override a's rule settings entirely.
// - Everything else is merged via Object.assign
function mergeConfigs(a/*: stylelint$config*/, b/*: stylelint$config*/)/*: stylelint$config*/ {
const pluginMerger = {}
if (a.plugins || b.plugins) {
pluginMerger.plugins = []
if (a.plugins) {
pluginMerger.plugins = pluginMerger.plugins.concat(a.plugins)
}
if (b.plugins) {
pluginMerger.plugins = _.uniq(pluginMerger.plugins.concat(b.plugins))
}
}
const processorMerger = {}
if (a.processors || b.processors) {
processorMerger.processors = []
if (a.processors) {
processorMerger.processors = processorMerger.processors.concat(a.processors)
}
if (b.processors) {
processorMerger.processors = _.uniq(processorMerger.processors.concat(b.processors))
}
}
const rulesMerger = {}
if (a.rules || b.rules) {
rulesMerger.rules = Object.assign({}, a.rules, b.rules)
}
const result = Object.assign({}, a, b, processorMerger, pluginMerger, rulesMerger)
return result
}
function addPluginFunctions(config/*: stylelint$config*/)/*: stylelint$config*/ {
if (!config.plugins) return config
const normalizedPlugins = Array.isArray(config.plugins) ? config.plugins : [config.plugins]
const pluginFunctions = normalizedPlugins.reduce((result, pluginLookup) => {
let pluginImport = dynamicRequire(pluginLookup)
// Handle either ES6 or CommonJS modules
pluginImport = pluginImport.default || pluginImport
// A plugin can export either a single rule definition
// or an array of them
const normalizedPluginImport = Array.isArray(pluginImport) ? pluginImport : [pluginImport]
normalizedPluginImport.forEach(pluginRuleDefinition => {
if (!pluginRuleDefinition.ruleName) {
throw configurationError("stylelint v3+ requires plugins to expose a ruleName. " + `The plugin "${pluginLookup}" is not doing this, so will not work ` + "with stylelint v3+. Please file an issue with the plugin.")
}
if (!_.includes(pluginRuleDefinition.ruleName, "/")) {
throw configurationError("stylelint v7+ requires plugin rules to be namspaced, " + "i.e. only `plugin-namespace/plugin-rule-name` plugin rule names are supported. " + `The plugin rule "${pluginRuleDefinition.ruleName}" does not do this, so will not work. ` + "Please file an issue with the plugin.")
}
result[pluginRuleDefinition.ruleName] = pluginRuleDefinition.rule
})
return result
}, {})
config.pluginFunctions = pluginFunctions
return config
}
function normalizeAllRuleSettings(config/*: stylelint$config*/)/*: stylelint$config*/ {
const normalizedRules = {}
if (!config.rules) return config
Object.keys(config.rules).forEach(ruleName => {
const rawRuleSettings = _.get(config, [ "rules", ruleName ])
const rule = rules[ruleName] || _.get(config, [ "pluginFunctions", ruleName ])
if (!rule) {
throw configurationError(`Undefined rule ${ruleName}`)
}
normalizedRules[ruleName] = normalizeRuleSettings(rawRuleSettings, ruleName, _.get(rule, "primaryOptionArray"))
})
config.rules = normalizedRules
return config
}
// Given an array of processors strings, we want to add two
// properties to the augmented config:
// - codeProcessors: functions that will run on code as it comes in
// - resultProcessors: functions that will run on results as they go out
//
// To create these properties, we need to:
// - Find the processor module
// - Intialize the processor module by calling its functions with any
// provided options
// - Push the processor's code and result processors to their respective arrays
const processorCache = new Map()
function addProcessorFunctions(config/*: stylelint$config*/)/*: stylelint$config*/ {
if (!config.processors) return config
const codeProcessors = []
const resultProcessors = []
;[].concat(config.processors).forEach(processorConfig => {
const processorKey = JSON.stringify(processorConfig)
let initializedProcessor
if (processorCache.has(processorKey)) {
initializedProcessor = processorCache.get(processorKey)
} else {
processorConfig = [].concat(processorConfig)
const processorLookup = processorConfig[0]
const processorOptions = processorConfig[1]
let processor = dynamicRequire(processorLookup)
processor = processor.default || processor
initializedProcessor = processor(processorOptions)
processorCache.set(processorKey, initializedProcessor)
}
if (initializedProcessor && initializedProcessor.code) {
codeProcessors.push(initializedProcessor.code)
}
if (initializedProcessor && initializedProcessor.result) {
resultProcessors.push(initializedProcessor.result)
}
})
config.codeProcessors = codeProcessors
config.resultProcessors = resultProcessors
return config
}
module.exports = { augmentConfigExtended, augmentConfigFull }
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | //#!/usr/bin/env node
/* @flow */
"use strict"
const getModulePath = require("./utils/getModulePath")
const getStdin = require("get-stdin")
const meow = require("meow")
const needlessDisablesStringFormatter = require("./formatters/needlessDisablesStringFormatter")
const path = require("path")
const resolveFrom = require("resolve-from")
const standalone = require("./standalone")
const dynamicRequire = require("./dynamicRequire")
const minimistOptions = {
default: {
config: false,
f: "string",
q: false,
},
alias: {
f: "formatter",
h: "help",
i: "ignore-path",
id: "ignore-disables",
q: "quiet",
rd: "report-needless-disables",
s: "syntax",
v: "version",
aei: "allow-empty-input",
},
boolean: [
"allow-empty-input",
"color",
"help",
"ignore-disables",
"no-color",
"quiet",
"version",
],
}
const meowOptions = {
help: `
Usage: stylelint [input] [options]
Input: Files(s), glob(s), or nothing to use stdin.
If an input argument is wrapped in quotation marks, it will be passed to
node-glob for cross-platform glob support. node_modules and
bower_components are always ignored. You can also pass no input and use
stdin, instead.
Options:
--config
Path to a specific configuration file (JSON, YAML, or CommonJS), or the
name of a module in node_modules that points to one. If no --config
argument is provided, stylelint will search for configuration files in
the following places, in this order:
- a stylelint property in package.json
- a .stylelintrc file (with or without filename extension:
.json, .yaml, .yml, and .js are available)
- a stylelint.config.js file exporting a JS object
The search will begin in the working directory and move up the directory
tree until a configuration file is found.
--config-basedir
An absolute path to the directory that relative paths defining "extends"
and "plugins" are *relative to*. Only necessary if these values are
relative paths.
--ignore-path, -i
Path to a file containing patterns that describe files to ignore. The
path can be absolute or relative to process.cwd(). By default, stylelint
looks for .stylelintignore in process.cwd().
--syntax, -s
Specify a non-standard syntax. Options: "scss", "less", "sugarss".
If you do not specify a syntax, non-standard syntaxes will be
automatically inferred by the file extensions .scss, .less, and .sss.
--custom-syntax
Module name or path to a JS file exporting a PostCSS-compatible syntax.
--stdin-filename
A filename to assign stdin input.
--ignore-disables, --id
Ignore styleline-disable comments.
--cache [default: false]
Store the info about processed files in order to only operate on the
changed ones the next time you run stylelint. By default, the cache
is stored in "./.stylelintcache". To adjust this, use --cache-location.
--cache-location [default: '.stylelintcache']
Path to a file or directory to be used for the cache location.
Default is "./.stylelintcache". If a directory is specified, a cache
file will be created inside the specified folder, with a name derived
from a hash of the current working directory.
If the directory for the cache does not exist, make sure you add a trailing "/"
on \*nix systems or "\" on Windows. Otherwise the path will be assumed to be a file.
--formatter, -f [default: "string"]
The output formatter: "json", "string" or "verbose".
--custom-formatter
Path to a JS file exporting a custom formatting function.
--quiet, -q
Only register warnings for rules with an "error"-level severity (ignore
"warning"-level).
--color
--no-color
Force enabling/disabling of color.
--allow-empty-input, -aei
If no files match glob pattern, exits without throwing an error.
--report-needless-disables, --rd
Report stylelint-disable comments that are not blocking a lint warning.
If you provide the argument "error", the process will exit with code 2
if needless disables are found.
--version, -v
Show the currently installed version of stylelint.
`,
pkg: "../package.json",
}
const cli = meow(meowOptions, minimistOptions)
let formatter = cli.flags.formatter
Iif (cli.flags.customFormatter) {
const customFormatter = path.isAbsolute(cli.flags.customFormatter) ? cli.flags.customFormatter : path.join(process.cwd(), cli.flags.customFormatter)
formatter = dynamicRequire(customFormatter)
}
const optionsBase/*: Object*/ = {
formatter,
configOverrides: {},
}
Iif (cli.flags.quiet) {
optionsBase.configOverrides.quiet = cli.flags.quiet
}
Iif (cli.flags.syntax) {
optionsBase.syntax = cli.flags.syntax
}
Iif (cli.flags.customSyntax) {
optionsBase.customSyntax = getModulePath(process.cwd(), cli.flags.customSyntax)
}
Iif (cli.flags.config) {
// Should check these possibilities:
// a. name of a node_module
// b. absolute path
// c. relative path relative to `process.cwd()`.
// If none of the above work, we'll try a relative path starting
// in `process.cwd()`.
optionsBase.configFile = resolveFrom(process.cwd(), cli.flags.config) || path.join(process.cwd(), cli.flags.config)
}
Iif (cli.flags.configBasedir) {
optionsBase.configBasedir = path.isAbsolute(cli.flags.configBasedir) ? cli.flags.configBasedir : path.resolve(process.cwd(), cli.flags.configBasedir)
}
Iif (cli.flags.stdinFilename) {
optionsBase.codeFilename = cli.flags.stdinFilename
}
Iif (cli.flags.ignorePath) {
optionsBase.ignorePath = cli.flags.ignorePath
}
Iif (cli.flags.ignoreDisables) {
optionsBase.ignoreDisables = cli.flags.ignoreDisables
}
Iif (cli.flags.allowEmptyInput) {
optionsBase.allowEmptyInput = cli.flags.allowEmptyInput
}
Iif (cli.flags.cache) {
optionsBase.cache = true
}
Iif (cli.flags.cacheLocation) {
optionsBase.cacheLocation = cli.flags.cacheLocation
}
const reportNeedlessDisables = cli.flags.reportNeedlessDisables
Iif (reportNeedlessDisables) {
optionsBase.reportNeedlessDisables = reportNeedlessDisables
}
Promise.resolve().then(() => {
// Add input/code into options
Iif (cli.input.length) {
return Object.assign({}, optionsBase, {
files: cli.input,
})
}
return getStdin().then(stdin => Object.assign({}, optionsBase, {
code: stdin,
}))
}).then(options => {
Eif (!options.files && !options.code) {
cli.showHelp()
}
return standalone(options)
}).then((linted) => {
if (reportNeedlessDisables) {
process.stdout.write(needlessDisablesStringFormatter(linted.needlessDisables))
if (reportNeedlessDisables === "error") {
process.exitCode = 2
}
return
}
if (!linted.output) {
return
}
process.stdout.write(linted.output)
if (linted.errored) {
process.exitCode = 2
}
}).catch(err => {
console.log(err.stack) // eslint-disable-line no-console
const exitCode = typeof err.code === "number" ? err.code : 1
process.exit(exitCode)
})
|
| 1 2 3 4 5 6 7 8 9 10 | 1 | "use strict" module.exports = function (ruleName, rule) { return { ruleName, rule, } } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | /* @flow */
"use strict"
const augmentConfig = require("./augmentConfig")
const _ = require("lodash")
const cosmiconfig = require("cosmiconfig")
const createStylelintResult = require("./createStylelintResult")
const getConfigForFile = require("./getConfigForFile")
const getPostcssResult = require("./getPostcssResult")
const isPathIgnored = require("./isPathIgnored")
const lintSource = require("./lintSource")
// The stylelint "internal API" is passed among functions
// so that methods on a stylelint instance can invoke
// each other while sharing options and caches
module.exports = function (options/*: stylelint$options*/)/*: stylelint$internalApi*/ {
options = options || {}
const stylelint/*: Object*/ = { _options: options }
// Two separate explorers so they can each have their own transform
// function whose results are cached by cosmiconfig
stylelint._fullExplorer = cosmiconfig("stylelint", {
argv: false,
rcExtensions: true,
transform: _.partial(augmentConfig.augmentConfigFull, stylelint),
})
stylelint._extendExplorer = cosmiconfig(null, {
argv: false,
transform: _.partial(augmentConfig.augmentConfigExtended, stylelint),
})
stylelint._specifiedConfigCache = new Map()
stylelint._postcssResultCache = new Map()
stylelint._createStylelintResult = _.partial(createStylelintResult, stylelint)
stylelint._getPostcssResult = _.partial(getPostcssResult, stylelint)
stylelint._lintSource = _.partial(lintSource, stylelint)
stylelint.getConfigForFile = _.partial(getConfigForFile, stylelint)
stylelint.isPathIgnored = _.partial(isPathIgnored, stylelint)
return stylelint
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | 1 1 | /* @flow */
"use strict"
const _ = require("lodash")
module.exports = function (
stylelint/*: stylelint$internalApi*/,
postcssResult/*: Object*/,
filePath/*:: ?: string*/
)/*: Promise<stylelint$result>*/ {
const source = !postcssResult.root.source ? undefined : postcssResult.root.source.input.file || postcssResult.root.source.input.id
// Strip out deprecation warnings from the messages
const deprecationMessages = _.remove(postcssResult.messages, { stylelintType: "deprecation" })
const deprecations = deprecationMessages.map(deprecationMessage => {
return {
text: deprecationMessage.text,
reference: deprecationMessage.stylelintReference,
}
})
// Also strip out invalid options
const invalidOptionMessages = _.remove(postcssResult.messages, { stylelintType: "invalidOption" })
const invalidOptionWarnings = invalidOptionMessages.map(invalidOptionMessage => {
return {
text: invalidOptionMessage.text,
}
})
// This defines the stylelint result object that formatters receive
let stylelintResult = {
source,
deprecations,
invalidOptionWarnings,
errored: postcssResult.stylelint.stylelintError,
warnings: postcssResult.messages.map(message => {
return {
line: message.line,
column: message.column,
rule: message.rule,
severity: message.severity,
text: message.text,
}
}),
ignored: postcssResult.stylelint.ignored,
_postcssResult: postcssResult,
}
return stylelint.getConfigForFile(filePath).then((result) => {
const config = result.config
if (config.resultProcessors) {
config.resultProcessors.forEach(resultProcessor => {
// Result processors might just mutate the result object,
// or might return a new one
const returned = resultProcessor(stylelintResult, source)
if (returned) {
stylelintResult = returned
}
})
}
return stylelintResult
})
}
|
| 1 2 3 4 5 6 7 8 | 1 | "use strict" // This file exists to remove the need for Flow's ignore_non_literal_requires option module.exports = function (name) { return require(name) } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 1 1 1 1 1 1 1 1 1 1 1 1 | /* @flow */
"use strict"
const augmentConfigFull = require("./augmentConfig").augmentConfigFull
const configurationError = require("./utils/configurationError")
const path = require("path")
module.exports = function (
stylelint/*: stylelint$internalApi*/,
searchPath/*:: ?: string*/
)/*: Promise<?{ config: stylelint$config, filepath: string }>*/ {
searchPath = searchPath || process.cwd()
const optionsConfig = stylelint._options.config
Iif (optionsConfig !== undefined) {
const cached = stylelint._specifiedConfigCache.get(optionsConfig)
if (cached) return cached
// stylelint._fullExplorer (cosmiconfig) is already configured to
// run augmentConfigFull; but since we're making up the result here,
// we need to manually run the transform
const augmentedResult = augmentConfigFull(stylelint, {
config: optionsConfig,
// Add the extra path part so that we can get the directory without being
// confused
filepath: path.join(process.cwd(), "argument-config"),
})
stylelint._specifiedConfigCache.set(optionsConfig, augmentedResult)
return augmentedResult
}
return stylelint._fullExplorer.load(searchPath, stylelint._options.configFile).then(config => {
// If no config was found, try looking from process.cwd
Eif (!config) return stylelint._fullExplorer.load(process.cwd())
return config
}).then(config => {
Eif (!config) {
const ending = searchPath ? ` for ${searchPath}` : ""
throw configurationError(`No configuration provided${ending}`)
}
return config
})
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | 1 1 1 1 1 1 1 1 1 1 | /* @flow */
"use strict"
const fs = require("fs")
const lessSyntax = require("postcss-less")
const path = require("path")
const postcss = require("postcss")
const scssSyntax = require("postcss-scss")
const sugarssSyntax = require("sugarss")
const dynamicRequire = require("./dynamicRequire")
const postcssProcessor = postcss()
module.exports = function (stylelint/*: stylelint$internalApi*/)/*: Promise<?Object>*/ {
const options/*: {
code?: string,
codeFilename?: string,
filePath?: string,
codeProcessors?: Array<Function>,
syntax?: stylelint$syntaxes,
customSyntax?: string
}*/ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}
const cached/*: ?postcss$result*/ = stylelint._postcssResultCache.get(options.filePath)
if (cached) return Promise.resolve(cached)
let getCode
if (options.code !== undefined) {
getCode = Promise.resolve(options.code)
} else if (options.filePath) {
getCode = readFile(options.filePath)
}
if (!getCode) {
throw new Error("code or filePath required")
}
return getCode.then(code => {
const customSyntax = stylelint._options.customSyntax
let syntax = stylelint._options.syntax
if (customSyntax) {
try {
syntax = dynamicRequire(customSyntax)
} catch (e) {
throw new Error(`Cannot resolve custom syntax module ${customSyntax}`)
}
} else {
const fileExtension = path.extname(options.filePath || "")
if (syntax === "scss" || !syntax && fileExtension === ".scss") {
syntax = scssSyntax
} else if (syntax === "less" || !syntax && fileExtension === ".less") {
syntax = lessSyntax
} else if (syntax === "sugarss" || !syntax && fileExtension === ".sss") {
syntax = sugarssSyntax
} else if (syntax) {
throw new Error("You must use a valid syntax option, either: scss, less or sugarss")
}
}
const postcssOptions/*: postcss$options*/ = {}
postcssOptions.from = options.filePath
/*
* PostCSS allows for syntaxes that only contain a parser, however,
* it then expects the syntax to be set as the `parser` option rather than `syntax.
*/
if (syntax && !syntax.stringify) {
postcssOptions.parser = syntax
} else {
postcssOptions.syntax = syntax
}
const source = options.code ? options.codeFilename : options.filePath
let preProcessedCode = code
if (options.codeProcessors) {
options.codeProcessors.forEach(codeProcessor => {
preProcessedCode = codeProcessor(preProcessedCode, source)
})
}
return postcssProcessor.process(preProcessedCode, postcssOptions)
}).then(postcssResult => {
stylelint._postcssResultCache.set(options.filePath, postcssResult)
return postcssResult
})
}
function readFile(filePath/*: string*/)/*: Promise<string>*/ {
return new Promise((resolve, reject) => {
fs.readFile(filePath, "utf8", (err, content) => {
if (err) {
return reject(err)
}
resolve(content)
})
})
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const report = require("./utils/report")
const ruleMessages = require("./utils/ruleMessages")
const validateOptions = require("./utils/validateOptions")
const checkAgainstRule = require("./utils/checkAgainstRule")
const createPlugin = require("./createPlugin")
const createRuleTester = require("./testUtils/createRuleTester")
const createStylelint = require("./createStylelint")
const postcssPlugin = require("./postcssPlugin")
const rules = require("./rules")
const formatters = require("./formatters")
const standalone = require("./standalone")
const api = postcssPlugin
api.utils = {
report,
ruleMessages,
validateOptions,
checkAgainstRule,
}
api.lint = standalone
api.rules = rules
api.formatters = formatters
api.createPlugin = createPlugin
api.createRuleTester = createRuleTester
api.createLinter = createStylelint
module.exports = api
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 1 1 1 1 1 1 1 1 | /* @flow */
"use strict"
const ignore = require("ignore")
const micromatch = require("micromatch")
const path = require("path")
const alwaysIgnoredGlobs = require("./alwaysIgnoredGlobs")
// To find out if a path is ignored, we need to load the config,
// which may have an ignoreFiles property,
// and will have incorporated any .stylelintignore file that was found
// into its ignorePatterns property. We then check the path
// against these.
module.exports = function (
stylelint/*: stylelint$internalApi*/,
filePathArg/*:: ?: string*/
)/*: Promise<boolean>*/ {
const filePath = filePathArg // to please Flow
Eif (!filePath) {
return Promise.resolve(false)
}
return stylelint.getConfigForFile(filePath).then((result) => {
const config = result.config
const absoluteFilePath = path.isAbsolute(filePath) ? filePath : path.resolve(process.cwd(), filePath)
const ignoreFiles = alwaysIgnoredGlobs.concat(config.ignoreFiles || [])
if (micromatch(absoluteFilePath, ignoreFiles).length) {
return true
}
const ignorePatternsFilter = ignore().add(config.ignorePatterns).createFilter()
const filepathRelativeToCwd = path.relative(process.cwd(), filePath)
if (ignorePatternsFilter && !ignorePatternsFilter(filepathRelativeToCwd)) {
return true
}
return false
})
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | /* @flow */
"use strict"
const _ = require("lodash")
const assignDisabledRanges = require("./assignDisabledRanges")
const configurationError = require("./utils/configurationError")
const path = require("path")
const ruleDefinitions = require("./rules")
// Run stylelint on a PostCSS Result, either one that is provided
// or one that we create
module.exports = function (
stylelint/*: stylelint$internalApi*/,
options/*: {
code?: string,
codeFilename?: string, // Must be an absolute file path
filePath?: string, // Must be an absolute file path
existingPostcssResult?: Object,
}*/
)/*: Promise<Object>*/ {
options = options || {}
Iif (!options.filePath && options.code === undefined && !options.existingPostcssResult) {
return Promise.reject(new Error("You must provide filePath, code, or existingPostcssResult"))
}
const isCodeNotFile = options.code !== undefined
const inputFilePath = isCodeNotFile ? options.codeFilename : options.filePath
Iif (inputFilePath !== undefined && !path.isAbsolute(inputFilePath)) {
if (isCodeNotFile) {
return Promise.reject(new Error("codeFilename must be an absolute path"))
} else {
return Promise.reject(new Error("filePath must be an absolute path"))
}
}
const getIsIgnored = stylelint.isPathIgnored(inputFilePath).catch(err => {
if (isCodeNotFile && err.code === "ENOENT") return false
throw err
})
return getIsIgnored.then(isIgnored => {
Iif (isIgnored) {
const postcssResult = options.existingPostcssResult || createEmptyPostcssResult(inputFilePath)
postcssResult.stylelint = postcssResult.stylelint || {}
postcssResult.stylelint.ignored = true
postcssResult.standaloneIgnored = true // TODO: remove need for this
return postcssResult
}
const configSearchPath = stylelint._options.configFile || inputFilePath
const getConfig = stylelint.getConfigForFile(configSearchPath).catch(err => {
Iif (isCodeNotFile && err.code === "ENOENT") return stylelint.getConfigForFile(process.cwd())
throw err
})
return getConfig.then((result) => {
const config = result.config
const existingPostcssResult = options.existingPostcssResult
if (existingPostcssResult) {
return lintPostcssResult(stylelint, existingPostcssResult, config).then(() => existingPostcssResult)
}
return stylelint._getPostcssResult({
code: options.code,
codeFilename: options.codeFilename,
filePath: inputFilePath,
codeProcessors: config.codeProcessors,
}).then(postcssResult => {
return lintPostcssResult(stylelint, postcssResult, config).then(() => postcssResult)
})
})
})
}
function lintPostcssResult(
stylelint/*: stylelint$internalApi*/,
postcssResult/*: Object*/,
config/*: stylelint$config*/
)/*: Promise<>*/ {
postcssResult.stylelint = postcssResult.stylelint || {}
postcssResult.stylelint.ruleSeverities = {}
postcssResult.stylelint.customMessages = {}
postcssResult.stylelint.quiet = config.quiet
const postcssRoot = postcssResult.root
assignDisabledRanges(postcssRoot, postcssResult)
if (stylelint._options.reportNeedlessDisables || stylelint._options.ignoreDisables) {
postcssResult.stylelint.ignoreDisables = true
}
// Promises for the rules. Although the rule code runs synchronously now,
// the use of Promises makes it compatible with the possibility of async
// rules down the line.
const performRules = []
const rules = config.rules ? Object.keys(config.rules) : []
rules.forEach(ruleName => {
const ruleFunction = ruleDefinitions[ruleName] || _.get(config, [ "pluginFunctions", ruleName ])
if (ruleFunction === undefined) {
throw configurationError(`Undefined rule ${ruleName}`)
}
const ruleSettings = _.get(config, [ "rules", ruleName ])
if (ruleSettings === null || ruleSettings[0] === null) {
return
}
const primaryOption = ruleSettings[0]
const secondaryOptions = ruleSettings[1]
// Log the rule's severity in the PostCSS result
const defaultSeverity = config.defaultSeverity || "error"
postcssResult.stylelint.ruleSeverities[ruleName] = _.get(secondaryOptions, "severity", defaultSeverity)
postcssResult.stylelint.customMessages[ruleName] = _.get(secondaryOptions, "message")
const performRule = Promise.resolve().then(() => {
return ruleFunction(primaryOption, secondaryOptions)(postcssRoot, postcssResult)
})
performRules.push(performRule)
})
return Promise.all(performRules)
}
function createEmptyPostcssResult(filePath/*:: ?: string*/)/*: Object*/ {
return {
root: {
source: {
input: { file: filePath },
},
},
messages: [],
stylelint: { stylelintError: null },
}
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | 1 1 1 | /* @flow */
"use strict"
const _ = require("lodash")
module.exports = function (results/*: Array<stylelint$result>*/)/*: stylelint$needlessDisablesReport*/ {
const report = []
results.forEach(result => {
// File with `CssSyntaxError` have not `_postcssResult`
if (!result._postcssResult) {
return
}
const unused = { source: result.source, ranges: [] }
const rangeData = _.cloneDeep(result._postcssResult.stylelint.disabledRanges)
if (!rangeData) {
return
}
result.warnings.forEach(warning => {
const rule/*: string*/ = warning.rule
const ruleRanges = rangeData[rule]
if (ruleRanges) {
// Back to front so we get the *last* range that applies to the warning
for (const range of ruleRanges.reverse()) {
if (isWarningInRange(warning, range)) {
range.used = true
return
}
}
}
for (const range of rangeData.all.reverse()) {
if (isWarningInRange(warning, range)) {
range.used = true
return
}
}
})
Object.keys(rangeData).forEach(rule => {
rangeData[rule].forEach(range => {
// Is an equivalent range already marked as unused?
const alreadyMarkedUnused = unused.ranges.find(unusedRange => {
return unusedRange.start === range.start && unusedRange.end === range.end
})
// If this range is unused and no equivalent is marked,
// mark this range as unused
if (!range.used && !alreadyMarkedUnused) {
unused.ranges.push(range)
}
// If this range is used but an equivalent has been marked as unused,
// remove that equivalent. This can happen because of the duplication
// of ranges in rule-specific range sets and the "all" range set
if (range.used && alreadyMarkedUnused) {
_.remove(unused.ranges, alreadyMarkedUnused)
}
})
})
unused.ranges = _.sortBy(unused.ranges, [ "start", "end" ])
report.push(unused)
})
return report
}
function isWarningInRange(
warning/*: {
rule: string,
line: number,
}*/,
range/*: {
rules?: Array<string>,
start: number,
end?: number,
}*/
)/*: boolean*/ {
const rule = warning.rule,
line = warning.line
// Need to check if range.end exist, because line number type cannot be compared to undefined
return range.start <= line && (range.end !== undefined && range.end >= line || range.end === undefined) && (!range.rules || range.rules.indexOf(rule) !== -1)
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | 1 1 1 | /* @flow */
"use strict"
const _ = require("lodash")
const rules = require("./rules")
// Rule settings can take a number of forms, e.g.
// a. "rule-name": null
// b. "rule-name": [null, ...]
// c. "rule-name": primaryOption
// d. "rule-name": [primaryOption]
// e. "rule-name": [primaryOption, secondaryOption]
// Where primaryOption can be anything: primitive, Object, or Array.
//
// This function normalizes all the possibilities into the
// standard form: [primaryOption, secondaryOption]
// Except in the cases with null, a & b, in which case
// null is returned
module.exports = function (
rawSettings/*: stylelint$configRuleSettings*/,
ruleName/*: string*/,
// If primaryOptionArray is not provided, we try to get it from the
// rules themselves, which will not work for plugins
primaryOptionArray/*:: ?: boolean*/
)/*: [any, Object] | Array<any | [any, Object]> | null*/ {
if (rawSettings === null) {
return null
}
if (!Array.isArray(rawSettings)) {
return [rawSettings]
}
// Everything below is an array ...
if (rawSettings[0] === null) {
return null
}
// This cursed rule needs a special case
if (ruleName === "declaration-block-properties-order") {
if (rawSettings[0] === "alphabetical") {
return rawSettings
}
if (typeof rawSettings[0] === "string") {
return [rawSettings]
}
}
if (primaryOptionArray === undefined) {
const rule = rules[ruleName]
primaryOptionArray = _.get(rule, "primaryOptionArray")
}
if (!primaryOptionArray) {
return rawSettings
}
// Everything below is a rule that CAN have an array for a primary option ...
// (they might also have something else, e.g. rule-properties-order can
// have the string "alphabetical")
if (rawSettings.length === 1 && Array.isArray(rawSettings[0])) {
return rawSettings
}
if (rawSettings.length === 2 && !_.isPlainObject(rawSettings[0]) && _.isPlainObject(rawSettings[1])) {
return rawSettings
}
return [rawSettings]
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 1 1 1 1 1 | /* @flow */
"use strict"
const _ = require("lodash")
const createStylelint = require("./createStylelint")
const postcss = require("postcss")
const path = require("path")
module.exports = postcss.plugin("stylelint", function (options) {
options = options || {}
const tailoredOptions/*: Object*/ = options.rules
? { config: options }
: options
const stylelint = createStylelint(tailoredOptions)
return (root, result) => {
let filePath = options.from || _.get(root, "source.input.file")
if (filePath !== undefined && !path.isAbsolute(filePath)) {
filePath = path.join(process.cwd(), filePath)
}
return stylelint._lintSource({
filePath,
existingPostcssResult: result,
})
}
})
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | /* @flow */
"use strict"
const path = require("path")
const formatters/*: Object*/ = require("./formatters")
const createStylelint = require("./createStylelint")
const globby/*: Function*/ = require("globby")
const needlessDisables/*: Function*/ = require("./needlessDisables")
const alwaysIgnoredGlobs = require("./alwaysIgnoredGlobs")
const FileCache = require("./utils/FileCache")
const debug = require("debug")("stylelint:standalone")
const pkg = require("../package.json")
const hash = require("./utils/hash")
/*::type CssSyntaxErrorT = {
column: number;
file?: string;
input: {
column: number;
file?: string;
line: number;
source: string;
};
line: number;
message: string;
name: string;
reason: string;
source: string;
}*/
module.exports = function (options/*: stylelint$standaloneOptions */)/*: Promise<stylelint$standaloneReturnValue>*/ {
const files = options.files
const code = options.code
const codeFilename = options.codeFilename
const config = options.config
const configFile = options.configFile
const configBasedir = options.configBasedir
const configOverrides = options.configOverrides
const ignoreDisables = options.ignoreDisables
const ignorePath = options.ignorePath
const reportNeedlessDisables = options.reportNeedlessDisables
const formatter = options.formatter
const syntax = options.syntax
const customSyntax = options.customSyntax
const allowEmptyInput = options.allowEmptyInput
const cacheLocation = options.cacheLocation
const useCache = options.cache || false
let fileCache
const startTime = Date.now()
const isValidCode = typeof code === "string"
Iif (!files && !isValidCode || files && (code || isValidCode)) {
throw new Error("You must pass stylelint a `files` glob or a `code` string, though not both")
}
let formatterFunction
Eif (typeof formatter === "string") {
formatterFunction = formatters[formatter]
Iif (formatterFunction === undefined) {
return Promise.reject(new Error("You must use a valid formatter option: 'json', 'string', 'verbose', or a function"))
}
} else if (typeof formatter === "function") {
formatterFunction = formatter
} else {
formatterFunction = formatters.json
}
const stylelint = createStylelint({
config,
configFile,
configBasedir,
configOverrides,
ignoreDisables,
ignorePath,
reportNeedlessDisables,
syntax,
customSyntax,
})
Eif (!files) {
const absoluteCodeFilename = (codeFilename !== undefined && !path.isAbsolute(codeFilename))
? path.join(process.cwd(), codeFilename)
: codeFilename
return stylelint._lintSource({
code,
codeFilename: absoluteCodeFilename,
}).then(postcssResult => {
return stylelint._createStylelintResult(postcssResult)
}).catch(handleError).then(stylelintResult => {
return prepareReturnValue([stylelintResult])
})
}
let fileList = files
if (typeof fileList === "string") {
fileList = [fileList]
}
fileList = fileList.concat(
alwaysIgnoredGlobs.map(file => "!" + file)
)
if (useCache) {
const stylelintVersion = pkg.version
const hashOfConfig = hash(`${stylelintVersion}_${JSON.stringify(config)}`)
fileCache = new FileCache(cacheLocation, hashOfConfig)
} else {
// No need to calculate hash here, we just want to delete cache file.
fileCache = new FileCache(cacheLocation)
// Remove cache file if cache option is disabled
fileCache.destroy()
}
return globby(fileList).then(filePaths => {
if (!filePaths.length) {
if (allowEmptyInput === undefined || !allowEmptyInput) {
const message = (files => {
if (typeof files === "string") {
return `${files} does`
}
// seperate files into last (last file) and initial) all the others
const initial = files.slice(0)
const last = initial.pop()
// join into a comma seperated string of file names
const ending = (files.length > 1 ? `and ${last} do` : `${last} does`)
return `${initial.join(", ")} ${ending}`.trim()
})(files) + " not match any files"
const err/*: Object*/ = new Error(message)
err.code = 80
throw err
} else {
return Promise.all([])
}
}
let absoluteFilePaths = filePaths.map(filePath => {
const absoluteFilepath = (!path.isAbsolute(filePath))
? path.join(process.cwd(), filePath)
: path.normalize(filePath)
return absoluteFilepath
})
if (useCache) {
absoluteFilePaths = absoluteFilePaths.filter(fileCache.hasFileChanged.bind(fileCache))
}
const getStylelintResults = absoluteFilePaths.map(absoluteFilepath => {
debug(`Processing ${absoluteFilepath}`)
return stylelint._lintSource({
filePath: absoluteFilepath,
}).then(postcssResult => {
if (postcssResult.stylelint.stylelintError && useCache) {
debug(`${absoluteFilepath} contains linting errors and will not be cached.`)
fileCache.removeEntry(absoluteFilepath)
}
return stylelint._createStylelintResult(postcssResult, absoluteFilepath)
}).catch(handleError)
})
return Promise.all(getStylelintResults)
}).then(prepareReturnValue)
function prepareReturnValue(stylelintResults/*: Array<stylelint$result>*/)/*: stylelint$standaloneReturnValue*/ {
const errored = stylelintResults.some(result => result.errored)
const returnValue/*: stylelint$standaloneReturnValue*/ = {
errored,
output: formatterFunction(stylelintResults),
results: stylelintResults,
}
if (reportNeedlessDisables) {
returnValue.needlessDisables = needlessDisables(stylelintResults)
}
if (useCache) {
fileCache.reconcile()
}
debug(`Linting complete in ${Date.now() - startTime}ms`)
return returnValue
}
}
function handleError(error/*: Object*/) {
Iif (error.name === "CssSyntaxError") {
return convertCssSyntaxErrorToResult(error)
} else {
throw error
}
}
// By converting syntax errors to stylelint results,
// we can control their appearance in the formatted output
// and other tools like editor plugins can decide how to
// present them, as well
function convertCssSyntaxErrorToResult(error/*: CssSyntaxErrorT*/)/*: stylelint$result*/ {
if (error.name !== "CssSyntaxError") {
throw error
}
return {
source: error.file || "<input css 1>",
deprecations: [],
invalidOptionWarnings: [],
errored: true,
warnings: [{
line: error.line,
column: error.column,
rule: error.name,
severity: "error",
text: error.reason + " (" + error.name + ")",
}],
}
}
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 100% | (1 / 1) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (1 / 1) | |
| jsonFormatter.js | 33.33% | (2 / 6) | 100% | (0 / 0) | 0% | (0 / 1) | 40% | (2 / 5) | |
| needlessDisablesStringFormatter.js | 21.05% | (4 / 19) | 0% | (0 / 8) | 0% | (0 / 2) | 22.22% | (4 / 18) | |
| stringFormatter.js | 18.99% | (15 / 79) | 0% | (0 / 32) | 0% | (0 / 7) | 20.83% | (15 / 72) | |
| verboseFormatter.js | 11.43% | (4 / 35) | 0% | (0 / 16) | 0% | (0 / 1) | 12.12% | (4 / 33) |
| 1 2 3 4 5 6 7 8 9 | 1 | "use strict"
module.exports = {
json: require("./jsonFormatter"),
string: require("./stringFormatter"),
verbose: require("./verboseFormatter"),
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | 1 1 | "use strict"
const _ = require("lodash")
// Omit any properties starting with `_`, which are fake-private
module.exports = function (results) {
const cleanedResults = results.map(result => {
return _.omitBy(result, (value, key) => key[0] === "_")
})
return JSON.stringify(cleanedResults)
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 1 1 1 1 | "use strict"
const chalk = require("chalk")
const path = require("path")
function logFrom(fromValue) {
if (fromValue.charAt(0) === "<") return fromValue
return path.relative(process.cwd(), fromValue).split(path.sep).join("/")
}
module.exports = function (report) {
let output = ""
report.forEach(sourceReport => {
if (!sourceReport.ranges || sourceReport.ranges.length === 0) {
return
}
output += "\n"
output += chalk.underline(logFrom(sourceReport.source)) + "\n"
sourceReport.ranges.forEach(range => {
output += `start: ${range.start}`
if (range.end !== undefined) {
output += `, end: ${range.end}`
}
output += "\n"
})
})
return output
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const table = require("table")
const _ = require("lodash")
const chalk = require("chalk")
const path = require("path")
const stringWidth = require("string-width")
const symbols = require("log-symbols")
const utils = require("postcss-reporter/lib/util")
const MARGIN_WIDTHS = 9
const levelColors = {
info: "blue",
warning: "yellow",
error: "red",
}
function deprecationsFormatter(results) {
const allDeprecationWarnings = _.flatMap(results, "deprecations")
const uniqueDeprecationWarnings = _.uniqBy(allDeprecationWarnings, "text")
if (!uniqueDeprecationWarnings || !uniqueDeprecationWarnings.length) {
return ""
}
return uniqueDeprecationWarnings.reduce((output, warning) => {
output += chalk.yellow("Deprecation Warning: ")
output += warning.text
if (warning.reference) {
output += chalk.dim(" See: ")
output += chalk.dim.underline(warning.reference)
}
return output + "\n"
}, "\n")
}
function invalidOptionsFormatter(results) {
const allInvalidOptionWarnings = _.flatMap(results, r => r.invalidOptionWarnings.map(w => w.text))
const uniqueInvalidOptionWarnings = _.uniq(allInvalidOptionWarnings)
return uniqueInvalidOptionWarnings.reduce((output, warning) => {
output += chalk.red("Invalid Option: ")
output += warning
return output + "\n"
}, "\n")
}
function logFrom(fromValue) {
if (fromValue.charAt(0) === "<") return fromValue
return path.relative(process.cwd(), fromValue).split(path.sep).join("/")
}
function getMessageWidth(columnWidths) {
if (!process.stdout.isTTY) {
return columnWidths[3]
}
const availableWidth = process.stdout.columns < 80 ? 80 : process.stdout.columns
const fullWidth = _.sum(_.values(columnWidths))
// If there is no reason to wrap the text, we won't align the last column to the right
if (availableWidth > fullWidth + MARGIN_WIDTHS) {
return columnWidths[3]
}
return availableWidth - (fullWidth - columnWidths[3] + MARGIN_WIDTHS)
}
function formatter(messages, source) {
if (!messages.length) return ""
const orderedMessages = _.sortBy(messages, m => m.line ? 2 : 1, // positionless first
m => m.line, m => m.column)
// Create a list of column widths, needed to calculate
// the size of the message column and if needed wrap it.
const columnWidths = { 0: 1, 1: 1, 2: 1, 3: 1, 4: 1 }
const calculateWidths = function (columns) {
_.forOwn(columns, (value, key) => {
const normalisedValue = value ? value.toString() : value
columnWidths[key] = Math.max(columnWidths[key], stringWidth(normalisedValue))
})
return columns
}
let output = "\n"
if (source) {
output += chalk.underline(logFrom(source)) + "\n"
}
const cleanedMessages = orderedMessages.map(message => {
const location = utils.getLocation(message)
const severity = message.severity
const row = [ location.line || "", location.column || "", symbols[severity] ? chalk[levelColors[severity]](symbols[severity]) : severity, message.text
// Remove all control characters (newline, tab and etc)
.replace(/[\x01-\x1A]+/g, " ") // eslint-disable-line
.replace(/\.$/, "").replace(new RegExp(_.escapeRegExp("(" + message.rule + ")") + "$"), ""), chalk.dim(message.rule || "") ]
calculateWidths(row)
return row
})
output += table.table(cleanedMessages, {
border: table.getBorderCharacters("void"),
columns: {
0: { alignment: "right", width: columnWidths[0], paddingRight: 0 },
1: { alignment: "left", width: columnWidths[1] },
2: { alignment: "center", width: columnWidths[2] },
3: { alignment: "left", width: getMessageWidth(columnWidths), wrapWord: true },
4: { alignment: "left", width: columnWidths[4], paddingRight: 0 },
},
drawHorizontalLine: () => false,
}).split("\n").map(el => el.replace(/(\d+)\s+(\d+)/, (m, p1, p2) => chalk.dim(p1 + ":" + p2))).join("\n")
return output
}
module.exports = function (results) {
let output = invalidOptionsFormatter(results)
output += deprecationsFormatter(results)
output = results.reduce((output, result) => {
output += formatter(result.warnings, result.source)
return output
}, output)
// Ensure consistent padding
output = output.trim()
if (output !== "") {
output = "\n" + output + "\n\n"
}
return output
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 1 1 1 1 | "use strict"
const _ = require("lodash")
const chalk = require("chalk")
const stringFormatter = require("./stringFormatter")
module.exports = function (results) {
let output = stringFormatter(results)
if (output === "") {
output = "\n"
}
const sourceWord = results.length > 1 ? "sources" : "source"
const ignoredCount = results.filter(result => result.ignored).length
const checkedDisplay = ignoredCount ? `${results.length - ignoredCount} of ${results.length}` : results.length
output += chalk.underline(`${checkedDisplay} ${sourceWord} checked\n`)
results.forEach(result => {
let formatting = "green"
if (result.errored) {
formatting = "red"
} else if (result.warnings.length) {
formatting = "yellow"
} else if (result.ignored) {
formatting = "dim"
}
let sourceText = `${result.source}`
if (result.ignored) {
sourceText += " (ignored)"
}
output += _.get(chalk, formatting)(` ${sourceText}\n`)
})
const warnings = _.flatten(results.map(r => r.warnings))
const warningsBySeverity = _.groupBy(warnings, "severity")
const problemWord = warnings.length === 1 ? "problem" : "problems"
output += chalk.underline(`\n${warnings.length} ${problemWord} found\n`)
_.forOwn(warningsBySeverity, (warningList, severityLevel) => {
const warningsByRule = _.groupBy(warningList, "rule")
output += ` severity level "${severityLevel}": ${warningList.length}\n`
_.forOwn(warningsByRule, (list, rule) => {
output += chalk.dim(` ${rule}: ${list.length}\n`)
})
})
return output + "\n"
}
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| keywordSets.js | 100% | (58 / 58) | 100% | (0 / 0) | 100% | (1 / 1) | 100% | (58 / 58) | |
| namedColorData.js | 100% | (1 / 1) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (1 / 1) | |
| propertySets.js | 100% | (3 / 3) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (3 / 3) | |
| punctuationSets.js | 100% | (4 / 4) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (4 / 4) | |
| shorthandData.js | 100% | (1 / 1) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (1 / 1) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 27 27 70 1 | "use strict"
const _ = require("lodash")
const keywordSets = {}
keywordSets.nonLengthUnits = new Set([
// Relative length units
"%",
// Time length units
"s",
"ms",
// Angle
"deg",
"grad",
"turn",
"rad",
// Frequency
"Hz",
"kHz",
// Resolution
"dpi",
"dpcm",
"dppx",
])
keywordSets.lengthUnits = new Set([
// Relative length units
"em",
"ex",
"ch",
"rem",
// Viewport-percentage lengths
"vh",
"vw",
"vmin",
"vmax",
"vm",
// Absolute length units
"px",
"mm",
"cm",
"in",
"pt",
"pc",
"q",
// Flexible length units
"fr",
])
keywordSets.units = uniteSets(keywordSets.nonLengthUnits, keywordSets.lengthUnits)
keywordSets.colorFunctionNames = new Set([
"rgb",
"rgba",
"hsl",
"hsla",
"hwb",
"gray",
])
keywordSets.camelCaseFunctionNames = new Set([
"translateX",
"translateY",
"translateZ",
"scaleX",
"scaleY",
"scaleZ",
"rotateX",
"rotateY",
"rotateZ",
"skewX",
"skewY",
])
keywordSets.basicKeywords = new Set([
"initial",
"inherit",
"unset",
])
keywordSets.fontFamilyKeywords = uniteSets(keywordSets.basicKeywords, [
"serif",
"sans-serif",
"cursive",
"fantasy",
"monospace",
])
keywordSets.fontWeightRelativeKeywords = new Set([
"bolder",
"lighter",
])
keywordSets.fontWeightAbsoluteKeywords = new Set(["bold"])
keywordSets.fontWeightNumericKeywords = new Set([
"100",
"200",
"300",
"400",
"500",
"600",
"700",
"800",
"900",
])
keywordSets.fontWeightKeywords = uniteSets(
keywordSets.basicKeywords,
keywordSets.fontWeightRelativeKeywords,
keywordSets.fontWeightAbsoluteKeywords,
keywordSets.fontWeightNumericKeywords
)
keywordSets.animationNameKeywords = uniteSets(keywordSets.basicKeywords,
["none"]
)
keywordSets.animationTimingFunctionKeywords = uniteSets(keywordSets.basicKeywords, [
"linear",
"ease",
"ease-in",
"ease-in-out",
"ease-out",
"step-start",
"step-end",
"steps",
"cubic-bezier",
])
keywordSets.animationIterationCountKeywords = new Set(["infinite"])
keywordSets.animationDirectionKeywords = uniteSets(keywordSets.basicKeywords, [
"normal",
"reverse",
"alternate",
"alternate-reverse",
])
keywordSets.animationFillModeKeywords = new Set([
"none",
"forwards",
"backwards",
"both",
])
keywordSets.animationPlayStateKeywords = uniteSets(keywordSets.basicKeywords, [
"running",
"paused",
])
// cf. https://developer.mozilla.org/en-US/docs/Web/CSS/animation
keywordSets.animationShorthandKeywords = uniteSets(
keywordSets.basicKeywords,
keywordSets.animationNameKeywords,
keywordSets.animationTimingFunctionKeywords,
keywordSets.animationIterationCountKeywords,
keywordSets.animationDirectionKeywords,
keywordSets.animationFillModeKeywords,
keywordSets.animationPlayStateKeywords
)
// These are the ones that can have single-colon notation
keywordSets.levelOneAndTwoPseudoElements = new Set([
"before",
"after",
"first-line",
"first-letter",
])
// These are the ones that require double-colon notation
keywordSets.levelThreePseudoElements = new Set([
"before",
"after",
"first-line",
"first-letter",
"selection",
"spelling-error",
"grammar-error",
"backdrop",
"marker",
"placeholder",
"shadow",
"slotted",
"content",
])
keywordSets.pseudoElements = uniteSets(
keywordSets.levelOneAndTwoPseudoElements,
keywordSets.levelThreePseudoElements
)
keywordSets.aNPlusBNotationPseudoClasses = new Set([
"nth-child",
"nth-column",
"nth-last-child",
"nth-last-column",
"nth-last-of-type",
"nth-of-type",
])
keywordSets.linguisticPseudoClasses = new Set([
"dir",
"lang",
])
keywordSets.otherPseudoClasses = new Set([
"active",
"any-link",
"blank",
"checked",
"contains",
"current",
"default",
"disabled",
"drop",
"empty",
"enabled",
"first-child",
"first-of-type",
"focus",
"focus-within",
"fullscreen",
"future",
"has",
"host",
"host-context",
"hover",
"indeterminate",
"in-range",
"invalid",
"last-child",
"last-of-type",
"link",
"matches",
"not",
"only-child",
"only-of-type",
"optional",
"out-of-range",
"past",
"placeholder-shown",
"read-only",
"read-write",
"required",
"root",
"scope",
"target",
"user-error",
"user-invalid",
"val",
"valid",
"visited",
])
keywordSets.webkitProprietaryPseudoElements = new Set([
"scrollbar",
"scrollbar-button",
"scrollbar-track",
"scrollbar-track-piece",
"scrollbar-thumb",
"scrollbar-corner",
"resize",
])
keywordSets.webkitProprietaryPseudoClasses = new Set([
"horizontal",
"vertical",
"decrement",
"increment",
"start",
"end",
"double-button",
"single-button",
"no-button",
"corner-present",
"window-inactive",
])
keywordSets.pseudoClasses = uniteSets(
keywordSets.aNPlusBNotationPseudoClasses,
keywordSets.linguisticPseudoClasses,
keywordSets.otherPseudoClasses
)
keywordSets.shorthandTimeProperties = new Set([
"transition",
"animation",
])
keywordSets.longhandTimeProperties = new Set([
"transition-duration",
"transition-delay",
"animation-duration",
"animation-delay",
])
keywordSets.timeProperties = uniteSets(
keywordSets.shorthandTimeProperties,
keywordSets.longhandTimeProperties
)
keywordSets.camelCaseKeywords = new Set([
"optimizeSpeed",
"optimizeQuality",
"optimizeLegibility",
"geometricPrecision",
"currentColor",
"crispEdges",
"visiblePainted",
"visibleFill",
"visibleStroke",
"sRGB",
"linearRGB",
])
// https://developer.mozilla.org/docs/Web/CSS/counter-increment
keywordSets.counterIncrementKeywords = uniteSets(keywordSets.basicKeywords, ["none"])
keywordSets.counterResetKeywords = uniteSets(keywordSets.basicKeywords, ["none"])
keywordSets.gridRowKeywords = uniteSets(keywordSets.basicKeywords, [
"auto",
"span",
])
keywordSets.gridColumnKeywords = uniteSets(keywordSets.basicKeywords, [
"auto",
"span",
])
keywordSets.gridAreaKeywords = uniteSets(keywordSets.basicKeywords, [
"auto",
"span",
])
// https://developer.mozilla.org/ru/docs/Web/CSS/list-style-type
keywordSets.listStyleTypeKeywords = uniteSets(keywordSets.basicKeywords, [
"none",
"disc",
"circle",
"square",
"decimal",
"cjk-decimal",
"decimal-leading-zero",
"lower-roman",
"upper-roman",
"lower-greek",
"lower-alpha",
"lower-latin",
"upper-alpha",
"upper-latin",
"arabic-indic",
"armenian",
"bengali",
"cambodian",
"cjk-earthly-branch",
"cjk-ideographic",
"devanagari",
"ethiopic-numeric",
"georgian",
"gujarati",
"gurmukhi",
"hebrew",
"hiragana",
"hiragana-iroha",
"japanese-formal",
"japanese-informal",
"kannada",
"katakana",
"katakana-iroha",
"khmer",
"korean-hangul-formal",
"korean-hanja-formal",
"korean-hanja-informal",
"lao",
"lower-armenian",
"malayalam",
"mongolian",
"myanmar",
"oriya",
"persian",
"simp-chinese-formal",
"simp-chinese-informal",
"tamil",
"telugu",
"thai",
"tibetan",
"trad-chinese-formal",
"trad-chinese-informal",
"upper-armenian",
"disclosure-open",
"disclosure-closed",
// Non-standard extensions (without prefixe)
"ethiopic-halehame",
"ethiopic-halehame-am",
"ethiopic-halehame-ti-er",
"ethiopic-halehame-ti-et",
"hangul",
"hangul-consonant",
"urdu",
])
keywordSets.listStylePositionKeywords = uniteSets(keywordSets.basicKeywords, [
"inside",
"outside",
])
keywordSets.listStyleImageKeywords = uniteSets(keywordSets.basicKeywords, ["none"])
keywordSets.listStyleShorthandKeywords = uniteSets(
keywordSets.basicKeywords,
keywordSets.listStyleTypeKeywords,
keywordSets.listStylePositionKeywords,
keywordSets.listStyleImageKeywords
)
keywordSets.fontStyleKeywords = uniteSets(keywordSets.basicKeywords, [
"normal",
"italic",
"oblique",
])
keywordSets.fontVariantKeywords = uniteSets(keywordSets.basicKeywords, [
"normal",
"none",
"historical-forms",
"none",
"common-ligatures",
"no-common-ligatures",
"discretionary-ligatures",
"no-discretionary-ligatures",
"historical-ligatures",
"no-historical-ligatures",
"contextual",
"no-contextual",
"small-caps",
"small-caps",
"all-small-caps",
"petite-caps",
"all-petite-caps",
"unicase",
"titling-caps",
"lining-nums",
"oldstyle-nums",
"proportional-nums",
"tabular-nums",
"diagonal-fractions",
"stacked-fractions",
"ordinal",
"slashed-zero",
"jis78",
"jis83",
"jis90",
"jis04",
"simplified",
"traditional",
"full-width",
"proportional-width",
"ruby",
])
keywordSets.fontStretchKeywords = uniteSets(keywordSets.basicKeywords, [
"semi-condensed",
"condensed",
"extra-condensed",
"ultra-condensed",
"semi-expanded",
"expanded",
"extra-expanded",
"ultra-expanded",
])
keywordSets.fontSizeKeywords = uniteSets(keywordSets.basicKeywords, [
"xx-small",
"x-small",
"small",
"medium",
"large",
"x-large",
"xx-large",
"larger",
"smaller",
])
keywordSets.lineHeightKeywords = uniteSets(keywordSets.basicKeywords, ["normal"])
keywordSets.fontShorthandKeywords = uniteSets(
keywordSets.basicKeywords,
keywordSets.fontStyleKeywords,
keywordSets.fontVariantKeywords,
keywordSets.fontWeightKeywords,
keywordSets.fontStretchKeywords,
keywordSets.fontSizeKeywords,
keywordSets.lineHeightKeywords, keywordSets.fontFamilyKeywords
)
keywordSets.keyframeSelectorKeywords = new Set([
"from",
"to",
])
// https://developer.mozilla.org/en/docs/Web/CSS/At-rule
keywordSets.atRules = new Set([
"apply",
"annotation",
"character-variant",
"charset",
"counter-style",
"custom-media",
"custom-selector",
"document",
"font-face",
"font-feature-values",
"import",
"keyframes",
"media",
"namespace",
"nest",
"ornaments",
"page",
"styleset",
"stylistic",
"supports",
"swash",
"viewport",
])
// https://drafts.csswg.org/mediaqueries/#descdef-media-update
keywordSets.deprecatedMediaFeatureNames = new Set([
"device-aspect-ratio",
"device-height",
"device-width",
"max-device-aspect-ratio",
"max-device-height",
"max-device-width",
"min-device-aspect-ratio",
"min-device-height",
"min-device-width",
])
// https://drafts.csswg.org/mediaqueries/#descdef-media-update
keywordSets.mediaFeatureNames = uniteSets(keywordSets.deprecatedMediaFeatureNames, [
"any-hover",
"any-pointer",
"aspect-ratio",
"color",
"color-gamut",
"color-index",
"grid",
"height",
"hover",
"max-aspect-ratio",
"max-color",
"max-color-index",
"max-height",
"max-monochrome",
"max-resolution",
"max-width",
"min-aspect-ratio",
"min-color",
"min-color-index",
"min-height",
"min-monochrome",
"min-resolution",
"min-width",
"monochrome",
"orientation",
"overflow-block",
"overflow-inline",
"pointer",
"resolution",
"scan",
"scripting",
"update",
"width",
])
// https://www.w3.org/TR/CSS22/ui.html#system-colors
keywordSets.systemColors = new Set([
"activeborder",
"activecaption",
"appworkspace",
"background",
"buttonface",
"buttonhighlight",
"buttonshadow",
"buttontext",
"captiontext",
"graytext",
"highlight",
"highlighttext",
"inactiveborder",
"inactivecaption",
"inactivecaptiontext",
"infobackground",
"infotext",
"menu",
"menutext",
"scrollbar",
"threeddarkshadow",
"threedface",
"threedhighlight",
"threedlightshadow",
"threedshadow",
"window",
"windowframe",
"windowtext",
])
function uniteSets() {
const sets = Array.from(arguments)
return new Set(sets.reduce((result, set) => {
return result.concat(_.toArray(set))
}, []))
}
module.exports = keywordSets
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 | 1 | "use strict"
module.exports = {
"aliceblue": {
"hex": [
"#f0f8ff", "#fff0f8ff",
],
"func": [
"rgb(240,248,255)",
"rgba(240,248,255,1)",
"rgba(240,248,255,100%)",
"rgb(94%,97%,100%)",
"rgba(94%,97%,100%,1)",
"rgba(94%,97%,100%,100%)",
"hsl(208,100%,97%)",
"hsla(208,100%,97%,1)",
"hsla(208,100%,97%,100%)",
"hwb(208,94%,0%)",
"hwb(208,94%,0%,1)",
"hwb(208,94%,0%,100%)",
],
},
"antiquewhite": {
"hex": [
"#faebd7", "#fffaebd7",
],
"func": [
"rgb(250,235,215)",
"rgba(250,235,215,1)",
"rgba(250,235,215,100%)",
"rgb(98%,92%,84%)",
"rgba(98%,92%,84%,1)",
"rgba(98%,92%,84%,100%)",
"hsl(34,78%,91%)",
"hsla(34,78%,91%,1)",
"hsla(34,78%,91%,100%)",
"hwb(34,84%,2%)",
"hwb(34,84%,2%,1)",
"hwb(34,84%,2%,100%)",
],
},
"aqua": {
"hex": [
"#00ffff", "#ff00ffff", "#0ff", "#f0ff",
],
"func": [
"rgb(0,255,255)",
"rgba(0,255,255,1)",
"rgba(0,255,255,100%)",
"rgb(0%,100%,100%)",
"rgba(0%,100%,100%,1)",
"rgba(0%,100%,100%,100%)",
"hsl(180,100%,50%)",
"hsla(180,100%,50%,1)",
"hsla(180,100%,50%,100%)",
"hwb(180,0%,0%)",
"hwb(180,0%,0%,1)",
"hwb(180,0%,0%,100%)",
],
},
"aquamarine": {
"hex": [
"#7fffd4", "#ff7fffd4",
],
"func": [
"rgb(127,255,212)",
"rgba(127,255,212,1)",
"rgba(127,255,212,100%)",
"rgb(50%,100%,83%)",
"rgba(50%,100%,83%,1)",
"rgba(50%,100%,83%,100%)",
"hsl(160,100%,75%)",
"hsla(160,100%,75%,1)",
"hsla(160,100%,75%,100%)",
"hwb(160,50%,0%)",
"hwb(160,50%,0%,1)",
"hwb(160,50%,0%,100%)",
],
},
"azure": {
"hex": [
"#f0ffff", "#fff0ffff",
],
"func": [
"rgb(240,255,255)",
"rgba(240,255,255,1)",
"rgba(240,255,255,100%)",
"rgb(94%,100%,100%)",
"rgba(94%,100%,100%,1)",
"rgba(94%,100%,100%,100%)",
"hsl(180,100%,97%)",
"hsla(180,100%,97%,1)",
"hsla(180,100%,97%,100%)",
"hwb(180,94%,0%)",
"hwb(180,94%,0%,1)",
"hwb(180,94%,0%,100%)",
],
},
"beige": {
"hex": [
"#f5f5dc", "#fff5f5dc",
],
"func": [
"rgb(245,245,220)",
"rgba(245,245,220,1)",
"rgba(245,245,220,100%)",
"rgb(96%,96%,86%)",
"rgba(96%,96%,86%,1)",
"rgba(96%,96%,86%,100%)",
"hsl(60,56%,91%)",
"hsla(60,56%,91%,1)",
"hsla(60,56%,91%,100%)",
"hwb(60,86%,4%)",
"hwb(60,86%,4%,1)",
"hwb(60,86%,4%,100%)",
],
},
"bisque": {
"hex": [
"#ffe4c4", "#ffffe4c4",
],
"func": [
"rgb(255,228,196)",
"rgba(255,228,196,1)",
"rgba(255,228,196,100%)",
"rgb(100%,89%,77%)",
"rgba(100%,89%,77%,1)",
"rgba(100%,89%,77%,100%)",
"hsl(33,100%,88%)",
"hsla(33,100%,88%,1)",
"hsla(33,100%,88%,100%)",
"hwb(33,77%,0%)",
"hwb(33,77%,0%,1)",
"hwb(33,77%,0%,100%)",
],
},
"black": {
"hex": [
"#000000", "#ff000000", "#000", "#f000",
],
"func": [
"rgb(0,0,0)",
"rgba(0,0,0,1)",
"rgba(0,0,0,100%)",
"rgb(0%,0%,0%)",
"rgba(0%,0%,0%,1)",
"rgba(0%,0%,0%,100%)",
"hsl(0,0%,0%)",
"hsla(0,0%,0%,1)",
"hsla(0,0%,0%,100%)",
"hwb(0,0%,100%)",
"hwb(0,0%,100%,1)",
"hwb(0,0%,100%,100%)",
"gray(0)",
"gray(0,1)",
"gray(0,100%)",
"gray(0%)",
"gray(0%,1)",
"gray(0%,100%)",
],
},
"blanchedalmond": {
"hex": [
"#ffebcd", "#ffffebcd",
],
"func": [
"rgb(255,235,205)",
"rgba(255,235,205,1)",
"rgba(255,235,205,100%)",
"rgb(100%,92%,80%)",
"rgba(100%,92%,80%,1)",
"rgba(100%,92%,80%,100%)",
"hsl(36,100%,90%)",
"hsla(36,100%,90%,1)",
"hsla(36,100%,90%,100%)",
"hwb(36,80%,0%)",
"hwb(36,80%,0%,1)",
"hwb(36,80%,0%,100%)",
],
},
"blue": {
"hex": [
"#0000ff", "#ff0000ff", "#00f", "#f00f",
],
"func": [
"rgb(0,0,255)",
"rgba(0,0,255,1)",
"rgba(0,0,255,100%)",
"rgb(0%,0%,100%)",
"rgba(0%,0%,100%,1)",
"rgba(0%,0%,100%,100%)",
"hsl(240,100%,50%)",
"hsla(240,100%,50%,1)",
"hsla(240,100%,50%,100%)",
"hwb(240,0%,0%)",
"hwb(240,0%,0%,1)",
"hwb(240,0%,0%,100%)",
],
},
"blueviolet": {
"hex": [
"#8a2be2", "#ff8a2be2",
],
"func": [
"rgb(138,43,226)",
"rgba(138,43,226,1)",
"rgba(138,43,226,100%)",
"rgb(54%,17%,89%)",
"rgba(54%,17%,89%,1)",
"rgba(54%,17%,89%,100%)",
"hsl(271,76%,53%)",
"hsla(271,76%,53%,1)",
"hsla(271,76%,53%,100%)",
"hwb(271,17%,11%)",
"hwb(271,17%,11%,1)",
"hwb(271,17%,11%,100%)",
],
},
"brown": {
"hex": [
"#a52a2a", "#ffa52a2a",
],
"func": [
"rgb(165,42,42)",
"rgba(165,42,42,1)",
"rgba(165,42,42,100%)",
"rgb(65%,16%,16%)",
"rgba(65%,16%,16%,1)",
"rgba(65%,16%,16%,100%)",
"hsl(0,59%,41%)",
"hsla(0,59%,41%,1)",
"hsla(0,59%,41%,100%)",
"hwb(0,16%,35%)",
"hwb(0,16%,35%,1)",
"hwb(0,16%,35%,100%)",
],
},
"burlywood": {
"hex": [
"#deb887", "#ffdeb887",
],
"func": [
"rgb(222,184,135)",
"rgba(222,184,135,1)",
"rgba(222,184,135,100%)",
"rgb(87%,72%,53%)",
"rgba(87%,72%,53%,1)",
"rgba(87%,72%,53%,100%)",
"hsl(34,57%,70%)",
"hsla(34,57%,70%,1)",
"hsla(34,57%,70%,100%)",
"hwb(34,53%,13%)",
"hwb(34,53%,13%,1)",
"hwb(34,53%,13%,100%)",
],
},
"cadetblue": {
"hex": [
"#5f9ea0", "#ff5f9ea0",
],
"func": [
"rgb(95,158,160)",
"rgba(95,158,160,1)",
"rgba(95,158,160,100%)",
"rgb(37%,62%,63%)",
"rgba(37%,62%,63%,1)",
"rgba(37%,62%,63%,100%)",
"hsl(182,25%,50%)",
"hsla(182,25%,50%,1)",
"hsla(182,25%,50%,100%)",
"hwb(182,37%,37%)",
"hwb(182,37%,37%,1)",
"hwb(182,37%,37%,100%)",
],
},
"chartreuse": {
"hex": [
"#7fff00", "#ff7fff00",
],
"func": [
"rgb(127,255,0)",
"rgba(127,255,0,1)",
"rgba(127,255,0,100%)",
"rgb(50%,100%,0%)",
"rgba(50%,100%,0%,1)",
"rgba(50%,100%,0%,100%)",
"hsl(90,100%,50%)",
"hsla(90,100%,50%,1)",
"hsla(90,100%,50%,100%)",
"hwb(90,0%,0%)",
"hwb(90,0%,0%,1)",
"hwb(90,0%,0%,100%)",
],
},
"chocolate": {
"hex": [
"#d2691e", "#ffd2691e",
],
"func": [
"rgb(210,105,30)",
"rgba(210,105,30,1)",
"rgba(210,105,30,100%)",
"rgb(82%,41%,12%)",
"rgba(82%,41%,12%,1)",
"rgba(82%,41%,12%,100%)",
"hsl(25,75%,47%)",
"hsla(25,75%,47%,1)",
"hsla(25,75%,47%,100%)",
"hwb(25,12%,18%)",
"hwb(25,12%,18%,1)",
"hwb(25,12%,18%,100%)",
],
},
"coral": {
"hex": [
"#ff7f50", "#ffff7f50",
],
"func": [
"rgb(255,127,80)",
"rgba(255,127,80,1)",
"rgba(255,127,80,100%)",
"rgb(100%,50%,31%)",
"rgba(100%,50%,31%,1)",
"rgba(100%,50%,31%,100%)",
"hsl(16,100%,66%)",
"hsla(16,100%,66%,1)",
"hsla(16,100%,66%,100%)",
"hwb(16,31%,0%)",
"hwb(16,31%,0%,1)",
"hwb(16,31%,0%,100%)",
],
},
"cornflowerblue": {
"hex": [
"#6495ed", "#ff6495ed",
],
"func": [
"rgb(100,149,237)",
"rgba(100,149,237,1)",
"rgba(100,149,237,100%)",
"rgb(39%,58%,93%)",
"rgba(39%,58%,93%,1)",
"rgba(39%,58%,93%,100%)",
"hsl(219,79%,66%)",
"hsla(219,79%,66%,1)",
"hsla(219,79%,66%,100%)",
"hwb(219,39%,7%)",
"hwb(219,39%,7%,1)",
"hwb(219,39%,7%,100%)",
],
},
"cornsilk": {
"hex": [
"#fff8dc", "#fffff8dc",
],
"func": [
"rgb(255,248,220)",
"rgba(255,248,220,1)",
"rgba(255,248,220,100%)",
"rgb(100%,97%,86%)",
"rgba(100%,97%,86%,1)",
"rgba(100%,97%,86%,100%)",
"hsl(48,100%,93%)",
"hsla(48,100%,93%,1)",
"hsla(48,100%,93%,100%)",
"hwb(48,86%,0%)",
"hwb(48,86%,0%,1)",
"hwb(48,86%,0%,100%)",
],
},
"crimson": {
"hex": [
"#dc143c", "#ffdc143c",
],
"func": [
"rgb(220,20,60)",
"rgba(220,20,60,1)",
"rgba(220,20,60,100%)",
"rgb(86%,8%,24%)",
"rgba(86%,8%,24%,1)",
"rgba(86%,8%,24%,100%)",
"hsl(348,83%,47%)",
"hsla(348,83%,47%,1)",
"hsla(348,83%,47%,100%)",
"hwb(348,8%,14%)",
"hwb(348,8%,14%,1)",
"hwb(348,8%,14%,100%)",
],
},
"cyan": {
"hex": [
"#00ffff", "#ff00ffff", "#0ff", "#f0ff",
],
"func": [
"rgb(0,255,255)",
"rgba(0,255,255,1)",
"rgba(0,255,255,100%)",
"rgb(0%,100%,100%)",
"rgba(0%,100%,100%,1)",
"rgba(0%,100%,100%,100%)",
"hsl(180,100%,50%)",
"hsla(180,100%,50%,1)",
"hsla(180,100%,50%,100%)",
"hwb(180,0%,0%)",
"hwb(180,0%,0%,1)",
"hwb(180,0%,0%,100%)",
],
},
"darkblue": {
"hex": [
"#00008b", "#ff00008b",
],
"func": [
"rgb(0,0,139)",
"rgba(0,0,139,1)",
"rgba(0,0,139,100%)",
"rgb(0%,0%,55%)",
"rgba(0%,0%,55%,1)",
"rgba(0%,0%,55%,100%)",
"hsl(240,100%,27%)",
"hsla(240,100%,27%,1)",
"hsla(240,100%,27%,100%)",
"hwb(240,0%,45%)",
"hwb(240,0%,45%,1)",
"hwb(240,0%,45%,100%)",
],
},
"darkcyan": {
"hex": [
"#008b8b", "#ff008b8b",
],
"func": [
"rgb(0,139,139)",
"rgba(0,139,139,1)",
"rgba(0,139,139,100%)",
"rgb(0%,55%,55%)",
"rgba(0%,55%,55%,1)",
"rgba(0%,55%,55%,100%)",
"hsl(180,100%,27%)",
"hsla(180,100%,27%,1)",
"hsla(180,100%,27%,100%)",
"hwb(180,0%,45%)",
"hwb(180,0%,45%,1)",
"hwb(180,0%,45%,100%)",
],
},
"darkgoldenrod": {
"hex": [
"#b8860b", "#ffb8860b",
],
"func": [
"rgb(184,134,11)",
"rgba(184,134,11,1)",
"rgba(184,134,11,100%)",
"rgb(72%,53%,4%)",
"rgba(72%,53%,4%,1)",
"rgba(72%,53%,4%,100%)",
"hsl(43,89%,38%)",
"hsla(43,89%,38%,1)",
"hsla(43,89%,38%,100%)",
"hwb(43,4%,28%)",
"hwb(43,4%,28%,1)",
"hwb(43,4%,28%,100%)",
],
},
"darkgray": {
"hex": [
"#a9a9a9", "#ffa9a9a9",
],
"func": [
"rgb(169,169,169)",
"rgba(169,169,169,1)",
"rgba(169,169,169,100%)",
"rgb(66%,66%,66%)",
"rgba(66%,66%,66%,1)",
"rgba(66%,66%,66%,100%)",
"hsl(0,0%,66%)",
"hsla(0,0%,66%,1)",
"hsla(0,0%,66%,100%)",
"hwb(0,66%,34%)",
"hwb(0,66%,34%,1)",
"hwb(0,66%,34%,100%)",
],
},
"darkgreen": {
"hex": [
"#006400", "#ff006400",
],
"func": [
"rgb(0,100,0)",
"rgba(0,100,0,1)",
"rgba(0,100,0,100%)",
"rgb(0%,39%,0%)",
"rgba(0%,39%,0%,1)",
"rgba(0%,39%,0%,100%)",
"hsl(120,100%,20%)",
"hsla(120,100%,20%,1)",
"hsla(120,100%,20%,100%)",
"hwb(120,0%,61%)",
"hwb(120,0%,61%,1)",
"hwb(120,0%,61%,100%)",
],
},
"darkgrey": {
"hex": [
"#a9a9a9", "#ffa9a9a9",
],
"func": [
"rgb(169,169,169)",
"rgba(169,169,169,1)",
"rgba(169,169,169,100%)",
"rgb(66%,66%,66%)",
"rgba(66%,66%,66%,1)",
"rgba(66%,66%,66%,100%)",
"hsl(0,0%,66%)",
"hsla(0,0%,66%,1)",
"hsla(0,0%,66%,100%)",
"hwb(0,66%,34%)",
"hwb(0,66%,34%,1)",
"hwb(0,66%,34%,100%)",
"gray(169)",
"gray(169,1)",
"gray(169,100%)",
"gray(169%)",
"gray(169%,1)",
"gray(169%,100%)",
],
},
"darkkhaki": {
"hex": [
"#bdb76b", "#ffbdb76b",
],
"func": [
"rgb(189,183,107)",
"rgba(189,183,107,1)",
"rgba(189,183,107,100%)",
"rgb(74%,72%,42%)",
"rgba(74%,72%,42%,1)",
"rgba(74%,72%,42%,100%)",
"hsl(56,38%,58%)",
"hsla(56,38%,58%,1)",
"hsla(56,38%,58%,100%)",
"hwb(56,42%,26%)",
"hwb(56,42%,26%,1)",
"hwb(56,42%,26%,100%)",
],
},
"darkmagenta": {
"hex": [
"#8b008b", "#ff8b008b",
],
"func": [
"rgb(139,0,139)",
"rgba(139,0,139,1)",
"rgba(139,0,139,100%)",
"rgb(55%,0%,55%)",
"rgba(55%,0%,55%,1)",
"rgba(55%,0%,55%,100%)",
"hsl(300,100%,27%)",
"hsla(300,100%,27%,1)",
"hsla(300,100%,27%,100%)",
"hwb(300,0%,45%)",
"hwb(300,0%,45%,1)",
"hwb(300,0%,45%,100%)",
],
},
"darkolivegreen": {
"hex": [
"#556b2f", "#ff556b2f",
],
"func": [
"rgb(85,107,47)",
"rgba(85,107,47,1)",
"rgba(85,107,47,100%)",
"rgb(33%,42%,18%)",
"rgba(33%,42%,18%,1)",
"rgba(33%,42%,18%,100%)",
"hsl(82,39%,30%)",
"hsla(82,39%,30%,1)",
"hsla(82,39%,30%,100%)",
"hwb(82,18%,58%)",
"hwb(82,18%,58%,1)",
"hwb(82,18%,58%,100%)",
],
},
"darkorange": {
"hex": [
"#ff8c00", "#ffff8c00",
],
"func": [
"rgb(255,140,0)",
"rgba(255,140,0,1)",
"rgba(255,140,0,100%)",
"rgb(100%,55%,0%)",
"rgba(100%,55%,0%,1)",
"rgba(100%,55%,0%,100%)",
"hsl(33,100%,50%)",
"hsla(33,100%,50%,1)",
"hsla(33,100%,50%,100%)",
"hwb(33,0%,0%)",
"hwb(33,0%,0%,1)",
"hwb(33,0%,0%,100%)",
],
},
"darkorchid": {
"hex": [
"#9932cc", "#ff9932cc",
],
"func": [
"rgb(153,50,204)",
"rgba(153,50,204,1)",
"rgba(153,50,204,100%)",
"rgb(60%,20%,80%)",
"rgba(60%,20%,80%,1)",
"rgba(60%,20%,80%,100%)",
"hsl(280,61%,50%)",
"hsla(280,61%,50%,1)",
"hsla(280,61%,50%,100%)",
"hwb(280,20%,20%)",
"hwb(280,20%,20%,1)",
"hwb(280,20%,20%,100%)",
],
},
"darkred": {
"hex": [
"#8b0000", "#ff8b0000",
],
"func": [
"rgb(139,0,0)",
"rgba(139,0,0,1)",
"rgba(139,0,0,100%)",
"rgb(55%,0%,0%)",
"rgba(55%,0%,0%,1)",
"rgba(55%,0%,0%,100%)",
"hsl(0,100%,27%)",
"hsla(0,100%,27%,1)",
"hsla(0,100%,27%,100%)",
"hwb(0,0%,45%)",
"hwb(0,0%,45%,1)",
"hwb(0,0%,45%,100%)",
],
},
"darksalmon": {
"hex": [
"#e9967a", "#ffe9967a",
],
"func": [
"rgb(233,150,122)",
"rgba(233,150,122,1)",
"rgba(233,150,122,100%)",
"rgb(91%,59%,48%)",
"rgba(91%,59%,48%,1)",
"rgba(91%,59%,48%,100%)",
"hsl(15,72%,70%)",
"hsla(15,72%,70%,1)",
"hsla(15,72%,70%,100%)",
"hwb(15,48%,9%)",
"hwb(15,48%,9%,1)",
"hwb(15,48%,9%,100%)",
],
},
"darkseagreen": {
"hex": [
"#8fbc8f", "#ff8fbc8f",
],
"func": [
"rgb(143,188,143)",
"rgba(143,188,143,1)",
"rgba(143,188,143,100%)",
"rgb(56%,74%,56%)",
"rgba(56%,74%,56%,1)",
"rgba(56%,74%,56%,100%)",
"hsl(120,25%,65%)",
"hsla(120,25%,65%,1)",
"hsla(120,25%,65%,100%)",
"hwb(120,56%,26%)",
"hwb(120,56%,26%,1)",
"hwb(120,56%,26%,100%)",
],
},
"darkslateblue": {
"hex": [
"#483d8b", "#ff483d8b",
],
"func": [
"rgb(72,61,139)",
"rgba(72,61,139,1)",
"rgba(72,61,139,100%)",
"rgb(28%,24%,55%)",
"rgba(28%,24%,55%,1)",
"rgba(28%,24%,55%,100%)",
"hsl(248,39%,39%)",
"hsla(248,39%,39%,1)",
"hsla(248,39%,39%,100%)",
"hwb(248,24%,45%)",
"hwb(248,24%,45%,1)",
"hwb(248,24%,45%,100%)",
],
},
"darkslategray": {
"hex": [
"#2f4f4f", "#ff2f4f4f",
],
"func": [
"rgb(47,79,79)",
"rgba(47,79,79,1)",
"rgba(47,79,79,100%)",
"rgb(18%,31%,31%)",
"rgba(18%,31%,31%,1)",
"rgba(18%,31%,31%,100%)",
"hsl(180,25%,25%)",
"hsla(180,25%,25%,1)",
"hsla(180,25%,25%,100%)",
"hwb(180,18%,69%)",
"hwb(180,18%,69%,1)",
"hwb(180,18%,69%,100%)",
],
},
"darkslategrey": {
"hex": [
"#2f4f4f", "#ff2f4f4f",
],
"func": [
"rgb(47,79,79)",
"rgba(47,79,79,1)",
"rgba(47,79,79,100%)",
"rgb(18%,31%,31%)",
"rgba(18%,31%,31%,1)",
"rgba(18%,31%,31%,100%)",
"hsl(180,25%,25%)",
"hsla(180,25%,25%,1)",
"hsla(180,25%,25%,100%)",
"hwb(180,18%,69%)",
"hwb(180,18%,69%,1)",
"hwb(180,18%,69%,100%)",
],
},
"darkturquoise": {
"hex": [
"#00ced1", "#ff00ced1",
],
"func": [
"rgb(0,206,209)",
"rgba(0,206,209,1)",
"rgba(0,206,209,100%)",
"rgb(0%,81%,82%)",
"rgba(0%,81%,82%,1)",
"rgba(0%,81%,82%,100%)",
"hsl(181,100%,41%)",
"hsla(181,100%,41%,1)",
"hsla(181,100%,41%,100%)",
"hwb(181,0%,18%)",
"hwb(181,0%,18%,1)",
"hwb(181,0%,18%,100%)",
],
},
"darkviolet": {
"hex": [
"#9400d3", "#ff9400d3",
],
"func": [
"rgb(148,0,211)",
"rgba(148,0,211,1)",
"rgba(148,0,211,100%)",
"rgb(58%,0%,83%)",
"rgba(58%,0%,83%,1)",
"rgba(58%,0%,83%,100%)",
"hsl(282,100%,41%)",
"hsla(282,100%,41%,1)",
"hsla(282,100%,41%,100%)",
"hwb(282,0%,17%)",
"hwb(282,0%,17%,1)",
"hwb(282,0%,17%,100%)",
],
},
"deeppink": {
"hex": [
"#ff1493", "#ffff1493",
],
"func": [
"rgb(255,20,147)",
"rgba(255,20,147,1)",
"rgba(255,20,147,100%)",
"rgb(100%,8%,58%)",
"rgba(100%,8%,58%,1)",
"rgba(100%,8%,58%,100%)",
"hsl(328,100%,54%)",
"hsla(328,100%,54%,1)",
"hsla(328,100%,54%,100%)",
"hwb(328,8%,0%)",
"hwb(328,8%,0%,1)",
"hwb(328,8%,0%,100%)",
],
},
"deepskyblue": {
"hex": [
"#00bfff", "#ff00bfff",
],
"func": [
"rgb(0,191,255)",
"rgba(0,191,255,1)",
"rgba(0,191,255,100%)",
"rgb(0%,75%,100%)",
"rgba(0%,75%,100%,1)",
"rgba(0%,75%,100%,100%)",
"hsl(195,100%,50%)",
"hsla(195,100%,50%,1)",
"hsla(195,100%,50%,100%)",
"hwb(195,0%,0%)",
"hwb(195,0%,0%,1)",
"hwb(195,0%,0%,100%)",
],
},
"dimgray": {
"hex": [
"#696969", "#ff696969",
],
"func": [
"rgb(105,105,105)",
"rgba(105,105,105,1)",
"rgba(105,105,105,100%)",
"rgb(41%,41%,41%)",
"rgba(41%,41%,41%,1)",
"rgba(41%,41%,41%,100%)",
"hsl(0,0%,41%)",
"hsla(0,0%,41%,1)",
"hsla(0,0%,41%,100%)",
"hwb(0,41%,59%)",
"hwb(0,41%,59%,1)",
"hwb(0,41%,59%,100%)",
],
},
"dimgrey": {
"hex": [
"#696969", "#ff696969",
],
"func": [
"rgb(105,105,105)",
"rgba(105,105,105,1)",
"rgba(105,105,105,100%)",
"rgb(41%,41%,41%)",
"rgba(41%,41%,41%,1)",
"rgba(41%,41%,41%,100%)",
"hsl(0,0%,41%)",
"hsla(0,0%,41%,1)",
"hsla(0,0%,41%,100%)",
"hwb(0,41%,59%)",
"hwb(0,41%,59%,1)",
"hwb(0,41%,59%,100%)",
"gray(105)",
"gray(105,1)",
"gray(105,100%)",
"gray(105%)",
"gray(105%,1)",
"gray(105%,100%)",
],
},
"dodgerblue": {
"hex": [
"#1e90ff", "#ff1e90ff",
],
"func": [
"rgb(30,144,255)",
"rgba(30,144,255,1)",
"rgba(30,144,255,100%)",
"rgb(12%,56%,100%)",
"rgba(12%,56%,100%,1)",
"rgba(12%,56%,100%,100%)",
"hsl(210,100%,56%)",
"hsla(210,100%,56%,1)",
"hsla(210,100%,56%,100%)",
"hwb(210,12%,0%)",
"hwb(210,12%,0%,1)",
"hwb(210,12%,0%,100%)",
],
},
"firebrick": {
"hex": [
"#b22222", "#ffb22222",
],
"func": [
"rgb(178,34,34)",
"rgba(178,34,34,1)",
"rgba(178,34,34,100%)",
"rgb(70%,13%,13%)",
"rgba(70%,13%,13%,1)",
"rgba(70%,13%,13%,100%)",
"hsl(0,68%,42%)",
"hsla(0,68%,42%,1)",
"hsla(0,68%,42%,100%)",
"hwb(0,13%,30%)",
"hwb(0,13%,30%,1)",
"hwb(0,13%,30%,100%)",
],
},
"floralwhite": {
"hex": [
"#fffaf0", "#fffffaf0",
],
"func": [
"rgb(255,250,240)",
"rgba(255,250,240,1)",
"rgba(255,250,240,100%)",
"rgb(100%,98%,94%)",
"rgba(100%,98%,94%,1)",
"rgba(100%,98%,94%,100%)",
"hsl(40,100%,97%)",
"hsla(40,100%,97%,1)",
"hsla(40,100%,97%,100%)",
"hwb(40,94%,0%)",
"hwb(40,94%,0%,1)",
"hwb(40,94%,0%,100%)",
],
},
"forestgreen": {
"hex": [
"#228b22", "#ff228b22",
],
"func": [
"rgb(34,139,34)",
"rgba(34,139,34,1)",
"rgba(34,139,34,100%)",
"rgb(13%,55%,13%)",
"rgba(13%,55%,13%,1)",
"rgba(13%,55%,13%,100%)",
"hsl(120,61%,34%)",
"hsla(120,61%,34%,1)",
"hsla(120,61%,34%,100%)",
"hwb(120,13%,45%)",
"hwb(120,13%,45%,1)",
"hwb(120,13%,45%,100%)",
],
},
"fuchsia": {
"hex": [
"#ff00ff", "#ffff00ff", "#f0f", "#ff0f",
],
"func": [
"rgb(255,0,255)",
"rgba(255,0,255,1)",
"rgba(255,0,255,100%)",
"rgb(100%,0%,100%)",
"rgba(100%,0%,100%,1)",
"rgba(100%,0%,100%,100%)",
"hsl(300,100%,50%)",
"hsla(300,100%,50%,1)",
"hsla(300,100%,50%,100%)",
"hwb(300,0%,0%)",
"hwb(300,0%,0%,1)",
"hwb(300,0%,0%,100%)",
],
},
"gainsboro": {
"hex": [
"#dcdcdc", "#ffdcdcdc",
],
"func": [
"rgb(220,220,220)",
"rgba(220,220,220,1)",
"rgba(220,220,220,100%)",
"rgb(86%,86%,86%)",
"rgba(86%,86%,86%,1)",
"rgba(86%,86%,86%,100%)",
"hsl(0,0%,86%)",
"hsla(0,0%,86%,1)",
"hsla(0,0%,86%,100%)",
"hwb(0,86%,14%)",
"hwb(0,86%,14%,1)",
"hwb(0,86%,14%,100%)",
],
},
"ghostwhite": {
"hex": [
"#f8f8ff", "#fff8f8ff",
],
"func": [
"rgb(248,248,255)",
"rgba(248,248,255,1)",
"rgba(248,248,255,100%)",
"rgb(97%,97%,100%)",
"rgba(97%,97%,100%,1)",
"rgba(97%,97%,100%,100%)",
"hsl(240,100%,99%)",
"hsla(240,100%,99%,1)",
"hsla(240,100%,99%,100%)",
"hwb(240,97%,0%)",
"hwb(240,97%,0%,1)",
"hwb(240,97%,0%,100%)",
],
},
"gold": {
"hex": [
"#ffd700", "#ffffd700",
],
"func": [
"rgb(255,215,0)",
"rgba(255,215,0,1)",
"rgba(255,215,0,100%)",
"rgb(100%,84%,0%)",
"rgba(100%,84%,0%,1)",
"rgba(100%,84%,0%,100%)",
"hsl(51,100%,50%)",
"hsla(51,100%,50%,1)",
"hsla(51,100%,50%,100%)",
"hwb(51,0%,0%)",
"hwb(51,0%,0%,1)",
"hwb(51,0%,0%,100%)",
],
},
"goldenrod": {
"hex": [
"#daa520", "#ffdaa520",
],
"func": [
"rgb(218,165,32)",
"rgba(218,165,32,1)",
"rgba(218,165,32,100%)",
"rgb(85%,65%,13%)",
"rgba(85%,65%,13%,1)",
"rgba(85%,65%,13%,100%)",
"hsl(43,74%,49%)",
"hsla(43,74%,49%,1)",
"hsla(43,74%,49%,100%)",
"hwb(43,13%,15%)",
"hwb(43,13%,15%,1)",
"hwb(43,13%,15%,100%)",
],
},
"gray": {
"hex": [
"#808080", "#ff808080",
],
"func": [
"rgb(128,128,128)",
"rgba(128,128,128,1)",
"rgba(128,128,128,100%)",
"rgb(50%,50%,50%)",
"rgba(50%,50%,50%,1)",
"rgba(50%,50%,50%,100%)",
"hsl(0,0%,50%)",
"hsla(0,0%,50%,1)",
"hsla(0,0%,50%,100%)",
"hwb(0,50%,50%)",
"hwb(0,50%,50%,1)",
"hwb(0,50%,50%,100%)",
],
},
"green": {
"hex": [
"#008000", "#ff008000",
],
"func": [
"rgb(0,128,0)",
"rgba(0,128,0,1)",
"rgba(0,128,0,100%)",
"rgb(0%,50%,0%)",
"rgba(0%,50%,0%,1)",
"rgba(0%,50%,0%,100%)",
"hsl(120,100%,25%)",
"hsla(120,100%,25%,1)",
"hsla(120,100%,25%,100%)",
"hwb(120,0%,50%)",
"hwb(120,0%,50%,1)",
"hwb(120,0%,50%,100%)",
],
},
"greenyellow": {
"hex": [
"#adff2f", "#ffadff2f",
],
"func": [
"rgb(173,255,47)",
"rgba(173,255,47,1)",
"rgba(173,255,47,100%)",
"rgb(68%,100%,18%)",
"rgba(68%,100%,18%,1)",
"rgba(68%,100%,18%,100%)",
"hsl(84,100%,59%)",
"hsla(84,100%,59%,1)",
"hsla(84,100%,59%,100%)",
"hwb(84,18%,0%)",
"hwb(84,18%,0%,1)",
"hwb(84,18%,0%,100%)",
],
},
"grey": {
"hex": [
"#808080", "#ff808080",
],
"func": [
"rgb(128,128,128)",
"rgba(128,128,128,1)",
"rgba(128,128,128,100%)",
"rgb(50%,50%,50%)",
"rgba(50%,50%,50%,1)",
"rgba(50%,50%,50%,100%)",
"hsl(0,0%,50%)",
"hsla(0,0%,50%,1)",
"hsla(0,0%,50%,100%)",
"hwb(0,50%,50%)",
"hwb(0,50%,50%,1)",
"hwb(0,50%,50%,100%)",
"gray(128)",
"gray(128,1)",
"gray(128,100%)",
"gray(128%)",
"gray(128%,1)",
"gray(128%,100%)",
],
},
"honeydew": {
"hex": [
"#f0fff0", "#fff0fff0",
],
"func": [
"rgb(240,255,240)",
"rgba(240,255,240,1)",
"rgba(240,255,240,100%)",
"rgb(94%,100%,94%)",
"rgba(94%,100%,94%,1)",
"rgba(94%,100%,94%,100%)",
"hsl(120,100%,97%)",
"hsla(120,100%,97%,1)",
"hsla(120,100%,97%,100%)",
"hwb(120,94%,0%)",
"hwb(120,94%,0%,1)",
"hwb(120,94%,0%,100%)",
],
},
"hotpink": {
"hex": [
"#ff69b4", "#ffff69b4",
],
"func": [
"rgb(255,105,180)",
"rgba(255,105,180,1)",
"rgba(255,105,180,100%)",
"rgb(100%,41%,71%)",
"rgba(100%,41%,71%,1)",
"rgba(100%,41%,71%,100%)",
"hsl(330,100%,71%)",
"hsla(330,100%,71%,1)",
"hsla(330,100%,71%,100%)",
"hwb(330,41%,0%)",
"hwb(330,41%,0%,1)",
"hwb(330,41%,0%,100%)",
],
},
"indianred": {
"hex": [
"#cd5c5c", "#ffcd5c5c",
],
"func": [
"rgb(205,92,92)",
"rgba(205,92,92,1)",
"rgba(205,92,92,100%)",
"rgb(80%,36%,36%)",
"rgba(80%,36%,36%,1)",
"rgba(80%,36%,36%,100%)",
"hsl(0,53%,58%)",
"hsla(0,53%,58%,1)",
"hsla(0,53%,58%,100%)",
"hwb(0,36%,20%)",
"hwb(0,36%,20%,1)",
"hwb(0,36%,20%,100%)",
],
},
"indigo": {
"hex": [
"#4b0082", "#ff4b0082",
],
"func": [
"rgb(75,0,130)",
"rgba(75,0,130,1)",
"rgba(75,0,130,100%)",
"rgb(29%,0%,51%)",
"rgba(29%,0%,51%,1)",
"rgba(29%,0%,51%,100%)",
"hsl(275,100%,25%)",
"hsla(275,100%,25%,1)",
"hsla(275,100%,25%,100%)",
"hwb(275,0%,49%)",
"hwb(275,0%,49%,1)",
"hwb(275,0%,49%,100%)",
],
},
"ivory": {
"hex": [
"#fffff0", "#fffffff0",
],
"func": [
"rgb(255,255,240)",
"rgba(255,255,240,1)",
"rgba(255,255,240,100%)",
"rgb(100%,100%,94%)",
"rgba(100%,100%,94%,1)",
"rgba(100%,100%,94%,100%)",
"hsl(60,100%,97%)",
"hsla(60,100%,97%,1)",
"hsla(60,100%,97%,100%)",
"hwb(60,94%,0%)",
"hwb(60,94%,0%,1)",
"hwb(60,94%,0%,100%)",
],
},
"khaki": {
"hex": [
"#f0e68c", "#fff0e68c",
],
"func": [
"rgb(240,230,140)",
"rgba(240,230,140,1)",
"rgba(240,230,140,100%)",
"rgb(94%,90%,55%)",
"rgba(94%,90%,55%,1)",
"rgba(94%,90%,55%,100%)",
"hsl(54,77%,75%)",
"hsla(54,77%,75%,1)",
"hsla(54,77%,75%,100%)",
"hwb(54,55%,6%)",
"hwb(54,55%,6%,1)",
"hwb(54,55%,6%,100%)",
],
},
"lavender": {
"hex": [
"#e6e6fa", "#ffe6e6fa",
],
"func": [
"rgb(230,230,250)",
"rgba(230,230,250,1)",
"rgba(230,230,250,100%)",
"rgb(90%,90%,98%)",
"rgba(90%,90%,98%,1)",
"rgba(90%,90%,98%,100%)",
"hsl(240,67%,94%)",
"hsla(240,67%,94%,1)",
"hsla(240,67%,94%,100%)",
"hwb(240,90%,2%)",
"hwb(240,90%,2%,1)",
"hwb(240,90%,2%,100%)",
],
},
"lavenderblush": {
"hex": [
"#fff0f5", "#fffff0f5",
],
"func": [
"rgb(255,240,245)",
"rgba(255,240,245,1)",
"rgba(255,240,245,100%)",
"rgb(100%,94%,96%)",
"rgba(100%,94%,96%,1)",
"rgba(100%,94%,96%,100%)",
"hsl(340,100%,97%)",
"hsla(340,100%,97%,1)",
"hsla(340,100%,97%,100%)",
"hwb(340,94%,0%)",
"hwb(340,94%,0%,1)",
"hwb(340,94%,0%,100%)",
],
},
"lawngreen": {
"hex": [
"#7cfc00", "#ff7cfc00",
],
"func": [
"rgb(124,252,0)",
"rgba(124,252,0,1)",
"rgba(124,252,0,100%)",
"rgb(49%,99%,0%)",
"rgba(49%,99%,0%,1)",
"rgba(49%,99%,0%,100%)",
"hsl(90,100%,49%)",
"hsla(90,100%,49%,1)",
"hsla(90,100%,49%,100%)",
"hwb(90,0%,1%)",
"hwb(90,0%,1%,1)",
"hwb(90,0%,1%,100%)",
],
},
"lemonchiffon": {
"hex": [
"#fffacd", "#fffffacd",
],
"func": [
"rgb(255,250,205)",
"rgba(255,250,205,1)",
"rgba(255,250,205,100%)",
"rgb(100%,98%,80%)",
"rgba(100%,98%,80%,1)",
"rgba(100%,98%,80%,100%)",
"hsl(54,100%,90%)",
"hsla(54,100%,90%,1)",
"hsla(54,100%,90%,100%)",
"hwb(54,80%,0%)",
"hwb(54,80%,0%,1)",
"hwb(54,80%,0%,100%)",
],
},
"lightblue": {
"hex": [
"#add8e6", "#ffadd8e6",
],
"func": [
"rgb(173,216,230)",
"rgba(173,216,230,1)",
"rgba(173,216,230,100%)",
"rgb(68%,85%,90%)",
"rgba(68%,85%,90%,1)",
"rgba(68%,85%,90%,100%)",
"hsl(195,53%,79%)",
"hsla(195,53%,79%,1)",
"hsla(195,53%,79%,100%)",
"hwb(195,68%,10%)",
"hwb(195,68%,10%,1)",
"hwb(195,68%,10%,100%)",
],
},
"lightcoral": {
"hex": [
"#f08080", "#fff08080",
],
"func": [
"rgb(240,128,128)",
"rgba(240,128,128,1)",
"rgba(240,128,128,100%)",
"rgb(94%,50%,50%)",
"rgba(94%,50%,50%,1)",
"rgba(94%,50%,50%,100%)",
"hsl(0,79%,72%)",
"hsla(0,79%,72%,1)",
"hsla(0,79%,72%,100%)",
"hwb(0,50%,6%)",
"hwb(0,50%,6%,1)",
"hwb(0,50%,6%,100%)",
],
},
"lightcyan": {
"hex": [
"#e0ffff", "#ffe0ffff",
],
"func": [
"rgb(224,255,255)",
"rgba(224,255,255,1)",
"rgba(224,255,255,100%)",
"rgb(88%,100%,100%)",
"rgba(88%,100%,100%,1)",
"rgba(88%,100%,100%,100%)",
"hsl(180,100%,94%)",
"hsla(180,100%,94%,1)",
"hsla(180,100%,94%,100%)",
"hwb(180,88%,0%)",
"hwb(180,88%,0%,1)",
"hwb(180,88%,0%,100%)",
],
},
"lightgoldenrodyellow": {
"hex": [
"#fafad2", "#fffafad2",
],
"func": [
"rgb(250,250,210)",
"rgba(250,250,210,1)",
"rgba(250,250,210,100%)",
"rgb(98%,98%,82%)",
"rgba(98%,98%,82%,1)",
"rgba(98%,98%,82%,100%)",
"hsl(60,80%,90%)",
"hsla(60,80%,90%,1)",
"hsla(60,80%,90%,100%)",
"hwb(60,82%,2%)",
"hwb(60,82%,2%,1)",
"hwb(60,82%,2%,100%)",
],
},
"lightgray": {
"hex": [
"#d3d3d3", "#ffd3d3d3",
],
"func": [
"rgb(211,211,211)",
"rgba(211,211,211,1)",
"rgba(211,211,211,100%)",
"rgb(83%,83%,83%)",
"rgba(83%,83%,83%,1)",
"rgba(83%,83%,83%,100%)",
"hsl(0,0%,83%)",
"hsla(0,0%,83%,1)",
"hsla(0,0%,83%,100%)",
"hwb(0,83%,17%)",
"hwb(0,83%,17%,1)",
"hwb(0,83%,17%,100%)",
],
},
"lightgreen": {
"hex": [
"#90ee90", "#ff90ee90",
],
"func": [
"rgb(144,238,144)",
"rgba(144,238,144,1)",
"rgba(144,238,144,100%)",
"rgb(56%,93%,56%)",
"rgba(56%,93%,56%,1)",
"rgba(56%,93%,56%,100%)",
"hsl(120,73%,75%)",
"hsla(120,73%,75%,1)",
"hsla(120,73%,75%,100%)",
"hwb(120,56%,7%)",
"hwb(120,56%,7%,1)",
"hwb(120,56%,7%,100%)",
],
},
"lightgrey": {
"hex": [
"#d3d3d3", "#ffd3d3d3",
],
"func": [
"rgb(211,211,211)",
"rgba(211,211,211,1)",
"rgba(211,211,211,100%)",
"rgb(83%,83%,83%)",
"rgba(83%,83%,83%,1)",
"rgba(83%,83%,83%,100%)",
"hsl(0,0%,83%)",
"hsla(0,0%,83%,1)",
"hsla(0,0%,83%,100%)",
"hwb(0,83%,17%)",
"hwb(0,83%,17%,1)",
"hwb(0,83%,17%,100%)",
"gray(211)",
"gray(211,1)",
"gray(211,100%)",
"gray(211%)",
"gray(211%,1)",
"gray(211%,100%)",
],
},
"lightpink": {
"hex": [
"#ffb6c1", "#ffffb6c1",
],
"func": [
"rgb(255,182,193)",
"rgba(255,182,193,1)",
"rgba(255,182,193,100%)",
"rgb(100%,71%,76%)",
"rgba(100%,71%,76%,1)",
"rgba(100%,71%,76%,100%)",
"hsl(351,100%,86%)",
"hsla(351,100%,86%,1)",
"hsla(351,100%,86%,100%)",
"hwb(351,71%,0%)",
"hwb(351,71%,0%,1)",
"hwb(351,71%,0%,100%)",
],
},
"lightsalmon": {
"hex": [
"#ffa07a", "#ffffa07a",
],
"func": [
"rgb(255,160,122)",
"rgba(255,160,122,1)",
"rgba(255,160,122,100%)",
"rgb(100%,63%,48%)",
"rgba(100%,63%,48%,1)",
"rgba(100%,63%,48%,100%)",
"hsl(17,100%,74%)",
"hsla(17,100%,74%,1)",
"hsla(17,100%,74%,100%)",
"hwb(17,48%,0%)",
"hwb(17,48%,0%,1)",
"hwb(17,48%,0%,100%)",
],
},
"lightseagreen": {
"hex": [
"#20b2aa", "#ff20b2aa",
],
"func": [
"rgb(32,178,170)",
"rgba(32,178,170,1)",
"rgba(32,178,170,100%)",
"rgb(13%,70%,67%)",
"rgba(13%,70%,67%,1)",
"rgba(13%,70%,67%,100%)",
"hsl(177,70%,41%)",
"hsla(177,70%,41%,1)",
"hsla(177,70%,41%,100%)",
"hwb(177,13%,30%)",
"hwb(177,13%,30%,1)",
"hwb(177,13%,30%,100%)",
],
},
"lightskyblue": {
"hex": [
"#87cefa", "#ff87cefa",
],
"func": [
"rgb(135,206,250)",
"rgba(135,206,250,1)",
"rgba(135,206,250,100%)",
"rgb(53%,81%,98%)",
"rgba(53%,81%,98%,1)",
"rgba(53%,81%,98%,100%)",
"hsl(203,92%,75%)",
"hsla(203,92%,75%,1)",
"hsla(203,92%,75%,100%)",
"hwb(203,53%,2%)",
"hwb(203,53%,2%,1)",
"hwb(203,53%,2%,100%)",
],
},
"lightslategray": {
"hex": [
"#778899", "#ff778899", "#789", "#f789",
],
"func": [
"rgb(119,136,153)",
"rgba(119,136,153,1)",
"rgba(119,136,153,100%)",
"rgb(47%,53%,60%)",
"rgba(47%,53%,60%,1)",
"rgba(47%,53%,60%,100%)",
"hsl(210,14%,53%)",
"hsla(210,14%,53%,1)",
"hsla(210,14%,53%,100%)",
"hwb(210,47%,40%)",
"hwb(210,47%,40%,1)",
"hwb(210,47%,40%,100%)",
],
},
"lightslategrey": {
"hex": [
"#778899", "#ff778899", "#789", "#f789",
],
"func": [
"rgb(119,136,153)",
"rgba(119,136,153,1)",
"rgba(119,136,153,100%)",
"rgb(47%,53%,60%)",
"rgba(47%,53%,60%,1)",
"rgba(47%,53%,60%,100%)",
"hsl(210,14%,53%)",
"hsla(210,14%,53%,1)",
"hsla(210,14%,53%,100%)",
"hwb(210,47%,40%)",
"hwb(210,47%,40%,1)",
"hwb(210,47%,40%,100%)",
],
},
"lightsteelblue": {
"hex": [
"#b0c4de", "#ffb0c4de",
],
"func": [
"rgb(176,196,222)",
"rgba(176,196,222,1)",
"rgba(176,196,222,100%)",
"rgb(69%,77%,87%)",
"rgba(69%,77%,87%,1)",
"rgba(69%,77%,87%,100%)",
"hsl(214,41%,78%)",
"hsla(214,41%,78%,1)",
"hsla(214,41%,78%,100%)",
"hwb(214,69%,13%)",
"hwb(214,69%,13%,1)",
"hwb(214,69%,13%,100%)",
],
},
"lightyellow": {
"hex": [
"#ffffe0", "#ffffffe0",
],
"func": [
"rgb(255,255,224)",
"rgba(255,255,224,1)",
"rgba(255,255,224,100%)",
"rgb(100%,100%,88%)",
"rgba(100%,100%,88%,1)",
"rgba(100%,100%,88%,100%)",
"hsl(60,100%,94%)",
"hsla(60,100%,94%,1)",
"hsla(60,100%,94%,100%)",
"hwb(60,88%,0%)",
"hwb(60,88%,0%,1)",
"hwb(60,88%,0%,100%)",
],
},
"lime": {
"hex": [
"#00ff00", "#ff00ff00", "#0f0", "#f0f0",
],
"func": [
"rgb(0,255,0)",
"rgba(0,255,0,1)",
"rgba(0,255,0,100%)",
"rgb(0%,100%,0%)",
"rgba(0%,100%,0%,1)",
"rgba(0%,100%,0%,100%)",
"hsl(120,100%,50%)",
"hsla(120,100%,50%,1)",
"hsla(120,100%,50%,100%)",
"hwb(120,0%,0%)",
"hwb(120,0%,0%,1)",
"hwb(120,0%,0%,100%)",
],
},
"limegreen": {
"hex": [
"#32cd32", "#ff32cd32",
],
"func": [
"rgb(50,205,50)",
"rgba(50,205,50,1)",
"rgba(50,205,50,100%)",
"rgb(20%,80%,20%)",
"rgba(20%,80%,20%,1)",
"rgba(20%,80%,20%,100%)",
"hsl(120,61%,50%)",
"hsla(120,61%,50%,1)",
"hsla(120,61%,50%,100%)",
"hwb(120,20%,20%)",
"hwb(120,20%,20%,1)",
"hwb(120,20%,20%,100%)",
],
},
"linen": {
"hex": [
"#faf0e6", "#fffaf0e6",
],
"func": [
"rgb(250,240,230)",
"rgba(250,240,230,1)",
"rgba(250,240,230,100%)",
"rgb(98%,94%,90%)",
"rgba(98%,94%,90%,1)",
"rgba(98%,94%,90%,100%)",
"hsl(30,67%,94%)",
"hsla(30,67%,94%,1)",
"hsla(30,67%,94%,100%)",
"hwb(30,90%,2%)",
"hwb(30,90%,2%,1)",
"hwb(30,90%,2%,100%)",
],
},
"magenta": {
"hex": [
"#ff00ff", "#ffff00ff", "#f0f", "#ff0f",
],
"func": [
"rgb(255,0,255)",
"rgba(255,0,255,1)",
"rgba(255,0,255,100%)",
"rgb(100%,0%,100%)",
"rgba(100%,0%,100%,1)",
"rgba(100%,0%,100%,100%)",
"hsl(300,100%,50%)",
"hsla(300,100%,50%,1)",
"hsla(300,100%,50%,100%)",
"hwb(300,0%,0%)",
"hwb(300,0%,0%,1)",
"hwb(300,0%,0%,100%)",
],
},
"maroon": {
"hex": [
"#800000", "#ff800000",
],
"func": [
"rgb(128,0,0)",
"rgba(128,0,0,1)",
"rgba(128,0,0,100%)",
"rgb(50%,0%,0%)",
"rgba(50%,0%,0%,1)",
"rgba(50%,0%,0%,100%)",
"hsl(0,100%,25%)",
"hsla(0,100%,25%,1)",
"hsla(0,100%,25%,100%)",
"hwb(0,0%,50%)",
"hwb(0,0%,50%,1)",
"hwb(0,0%,50%,100%)",
],
},
"mediumaquamarine": {
"hex": [
"#66cdaa", "#ff66cdaa",
],
"func": [
"rgb(102,205,170)",
"rgba(102,205,170,1)",
"rgba(102,205,170,100%)",
"rgb(40%,80%,67%)",
"rgba(40%,80%,67%,1)",
"rgba(40%,80%,67%,100%)",
"hsl(160,51%,60%)",
"hsla(160,51%,60%,1)",
"hsla(160,51%,60%,100%)",
"hwb(160,40%,20%)",
"hwb(160,40%,20%,1)",
"hwb(160,40%,20%,100%)",
],
},
"mediumblue": {
"hex": [
"#0000cd", "#ff0000cd",
],
"func": [
"rgb(0,0,205)",
"rgba(0,0,205,1)",
"rgba(0,0,205,100%)",
"rgb(0%,0%,80%)",
"rgba(0%,0%,80%,1)",
"rgba(0%,0%,80%,100%)",
"hsl(240,100%,40%)",
"hsla(240,100%,40%,1)",
"hsla(240,100%,40%,100%)",
"hwb(240,0%,20%)",
"hwb(240,0%,20%,1)",
"hwb(240,0%,20%,100%)",
],
},
"mediumorchid": {
"hex": [
"#ba55d3", "#ffba55d3",
],
"func": [
"rgb(186,85,211)",
"rgba(186,85,211,1)",
"rgba(186,85,211,100%)",
"rgb(73%,33%,83%)",
"rgba(73%,33%,83%,1)",
"rgba(73%,33%,83%,100%)",
"hsl(288,59%,58%)",
"hsla(288,59%,58%,1)",
"hsla(288,59%,58%,100%)",
"hwb(288,33%,17%)",
"hwb(288,33%,17%,1)",
"hwb(288,33%,17%,100%)",
],
},
"mediumpurple": {
"hex": [
"#9370db", "#ff9370db",
],
"func": [
"rgb(147,112,219)",
"rgba(147,112,219,1)",
"rgba(147,112,219,100%)",
"rgb(58%,44%,86%)",
"rgba(58%,44%,86%,1)",
"rgba(58%,44%,86%,100%)",
"hsl(260,60%,65%)",
"hsla(260,60%,65%,1)",
"hsla(260,60%,65%,100%)",
"hwb(260,44%,14%)",
"hwb(260,44%,14%,1)",
"hwb(260,44%,14%,100%)",
],
},
"mediumseagreen": {
"hex": [
"#3cb371", "#ff3cb371",
],
"func": [
"rgb(60,179,113)",
"rgba(60,179,113,1)",
"rgba(60,179,113,100%)",
"rgb(24%,70%,44%)",
"rgba(24%,70%,44%,1)",
"rgba(24%,70%,44%,100%)",
"hsl(147,50%,47%)",
"hsla(147,50%,47%,1)",
"hsla(147,50%,47%,100%)",
"hwb(147,24%,30%)",
"hwb(147,24%,30%,1)",
"hwb(147,24%,30%,100%)",
],
},
"mediumslateblue": {
"hex": [
"#7b68ee", "#ff7b68ee",
],
"func": [
"rgb(123,104,238)",
"rgba(123,104,238,1)",
"rgba(123,104,238,100%)",
"rgb(48%,41%,93%)",
"rgba(48%,41%,93%,1)",
"rgba(48%,41%,93%,100%)",
"hsl(249,80%,67%)",
"hsla(249,80%,67%,1)",
"hsla(249,80%,67%,100%)",
"hwb(249,41%,7%)",
"hwb(249,41%,7%,1)",
"hwb(249,41%,7%,100%)",
],
},
"mediumspringgreen": {
"hex": [
"#00fa9a", "#ff00fa9a",
],
"func": [
"rgb(0,250,154)",
"rgba(0,250,154,1)",
"rgba(0,250,154,100%)",
"rgb(0%,98%,60%)",
"rgba(0%,98%,60%,1)",
"rgba(0%,98%,60%,100%)",
"hsl(157,100%,49%)",
"hsla(157,100%,49%,1)",
"hsla(157,100%,49%,100%)",
"hwb(157,0%,2%)",
"hwb(157,0%,2%,1)",
"hwb(157,0%,2%,100%)",
],
},
"mediumturquoise": {
"hex": [
"#48d1cc", "#ff48d1cc",
],
"func": [
"rgb(72,209,204)",
"rgba(72,209,204,1)",
"rgba(72,209,204,100%)",
"rgb(28%,82%,80%)",
"rgba(28%,82%,80%,1)",
"rgba(28%,82%,80%,100%)",
"hsl(178,60%,55%)",
"hsla(178,60%,55%,1)",
"hsla(178,60%,55%,100%)",
"hwb(178,28%,18%)",
"hwb(178,28%,18%,1)",
"hwb(178,28%,18%,100%)",
],
},
"mediumvioletred": {
"hex": [
"#c71585", "#ffc71585",
],
"func": [
"rgb(199,21,133)",
"rgba(199,21,133,1)",
"rgba(199,21,133,100%)",
"rgb(78%,8%,52%)",
"rgba(78%,8%,52%,1)",
"rgba(78%,8%,52%,100%)",
"hsl(322,81%,43%)",
"hsla(322,81%,43%,1)",
"hsla(322,81%,43%,100%)",
"hwb(322,8%,22%)",
"hwb(322,8%,22%,1)",
"hwb(322,8%,22%,100%)",
],
},
"midnightblue": {
"hex": [
"#191970", "#ff191970",
],
"func": [
"rgb(25,25,112)",
"rgba(25,25,112,1)",
"rgba(25,25,112,100%)",
"rgb(10%,10%,44%)",
"rgba(10%,10%,44%,1)",
"rgba(10%,10%,44%,100%)",
"hsl(240,64%,27%)",
"hsla(240,64%,27%,1)",
"hsla(240,64%,27%,100%)",
"hwb(240,10%,56%)",
"hwb(240,10%,56%,1)",
"hwb(240,10%,56%,100%)",
],
},
"mintcream": {
"hex": [
"#f5fffa", "#fff5fffa",
],
"func": [
"rgb(245,255,250)",
"rgba(245,255,250,1)",
"rgba(245,255,250,100%)",
"rgb(96%,100%,98%)",
"rgba(96%,100%,98%,1)",
"rgba(96%,100%,98%,100%)",
"hsl(150,100%,98%)",
"hsla(150,100%,98%,1)",
"hsla(150,100%,98%,100%)",
"hwb(150,96%,0%)",
"hwb(150,96%,0%,1)",
"hwb(150,96%,0%,100%)",
],
},
"mistyrose": {
"hex": [
"#ffe4e1", "#ffffe4e1",
],
"func": [
"rgb(255,228,225)",
"rgba(255,228,225,1)",
"rgba(255,228,225,100%)",
"rgb(100%,89%,88%)",
"rgba(100%,89%,88%,1)",
"rgba(100%,89%,88%,100%)",
"hsl(6,100%,94%)",
"hsla(6,100%,94%,1)",
"hsla(6,100%,94%,100%)",
"hwb(6,88%,0%)",
"hwb(6,88%,0%,1)",
"hwb(6,88%,0%,100%)",
],
},
"moccasin": {
"hex": [
"#ffe4b5", "#ffffe4b5",
],
"func": [
"rgb(255,228,181)",
"rgba(255,228,181,1)",
"rgba(255,228,181,100%)",
"rgb(100%,89%,71%)",
"rgba(100%,89%,71%,1)",
"rgba(100%,89%,71%,100%)",
"hsl(38,100%,85%)",
"hsla(38,100%,85%,1)",
"hsla(38,100%,85%,100%)",
"hwb(38,71%,0%)",
"hwb(38,71%,0%,1)",
"hwb(38,71%,0%,100%)",
],
},
"navajowhite": {
"hex": [
"#ffdead", "#ffffdead",
],
"func": [
"rgb(255,222,173)",
"rgba(255,222,173,1)",
"rgba(255,222,173,100%)",
"rgb(100%,87%,68%)",
"rgba(100%,87%,68%,1)",
"rgba(100%,87%,68%,100%)",
"hsl(36,100%,84%)",
"hsla(36,100%,84%,1)",
"hsla(36,100%,84%,100%)",
"hwb(36,68%,0%)",
"hwb(36,68%,0%,1)",
"hwb(36,68%,0%,100%)",
],
},
"navy": {
"hex": [
"#000080", "#ff000080",
],
"func": [
"rgb(0,0,128)",
"rgba(0,0,128,1)",
"rgba(0,0,128,100%)",
"rgb(0%,0%,50%)",
"rgba(0%,0%,50%,1)",
"rgba(0%,0%,50%,100%)",
"hsl(240,100%,25%)",
"hsla(240,100%,25%,1)",
"hsla(240,100%,25%,100%)",
"hwb(240,0%,50%)",
"hwb(240,0%,50%,1)",
"hwb(240,0%,50%,100%)",
],
},
"oldlace": {
"hex": [
"#fdf5e6", "#fffdf5e6",
],
"func": [
"rgb(253,245,230)",
"rgba(253,245,230,1)",
"rgba(253,245,230,100%)",
"rgb(99%,96%,90%)",
"rgba(99%,96%,90%,1)",
"rgba(99%,96%,90%,100%)",
"hsl(39,85%,95%)",
"hsla(39,85%,95%,1)",
"hsla(39,85%,95%,100%)",
"hwb(39,90%,1%)",
"hwb(39,90%,1%,1)",
"hwb(39,90%,1%,100%)",
],
},
"olive": {
"hex": [
"#808000", "#ff808000",
],
"func": [
"rgb(128,128,0)",
"rgba(128,128,0,1)",
"rgba(128,128,0,100%)",
"rgb(50%,50%,0%)",
"rgba(50%,50%,0%,1)",
"rgba(50%,50%,0%,100%)",
"hsl(60,100%,25%)",
"hsla(60,100%,25%,1)",
"hsla(60,100%,25%,100%)",
"hwb(60,0%,50%)",
"hwb(60,0%,50%,1)",
"hwb(60,0%,50%,100%)",
],
},
"olivedrab": {
"hex": [
"#6b8e23", "#ff6b8e23",
],
"func": [
"rgb(107,142,35)",
"rgba(107,142,35,1)",
"rgba(107,142,35,100%)",
"rgb(42%,56%,14%)",
"rgba(42%,56%,14%,1)",
"rgba(42%,56%,14%,100%)",
"hsl(80,60%,35%)",
"hsla(80,60%,35%,1)",
"hsla(80,60%,35%,100%)",
"hwb(80,14%,44%)",
"hwb(80,14%,44%,1)",
"hwb(80,14%,44%,100%)",
],
},
"orange": {
"hex": [
"#ffa500", "#ffffa500",
],
"func": [
"rgb(255,165,0)",
"rgba(255,165,0,1)",
"rgba(255,165,0,100%)",
"rgb(100%,65%,0%)",
"rgba(100%,65%,0%,1)",
"rgba(100%,65%,0%,100%)",
"hsl(39,100%,50%)",
"hsla(39,100%,50%,1)",
"hsla(39,100%,50%,100%)",
"hwb(39,0%,0%)",
"hwb(39,0%,0%,1)",
"hwb(39,0%,0%,100%)",
],
},
"orangered": {
"hex": [
"#ff4500", "#ffff4500",
],
"func": [
"rgb(255,69,0)",
"rgba(255,69,0,1)",
"rgba(255,69,0,100%)",
"rgb(100%,27%,0%)",
"rgba(100%,27%,0%,1)",
"rgba(100%,27%,0%,100%)",
"hsl(16,100%,50%)",
"hsla(16,100%,50%,1)",
"hsla(16,100%,50%,100%)",
"hwb(16,0%,0%)",
"hwb(16,0%,0%,1)",
"hwb(16,0%,0%,100%)",
],
},
"orchid": {
"hex": [
"#da70d6", "#ffda70d6",
],
"func": [
"rgb(218,112,214)",
"rgba(218,112,214,1)",
"rgba(218,112,214,100%)",
"rgb(85%,44%,84%)",
"rgba(85%,44%,84%,1)",
"rgba(85%,44%,84%,100%)",
"hsl(302,59%,65%)",
"hsla(302,59%,65%,1)",
"hsla(302,59%,65%,100%)",
"hwb(302,44%,15%)",
"hwb(302,44%,15%,1)",
"hwb(302,44%,15%,100%)",
],
},
"palegoldenrod": {
"hex": [
"#eee8aa", "#ffeee8aa",
],
"func": [
"rgb(238,232,170)",
"rgba(238,232,170,1)",
"rgba(238,232,170,100%)",
"rgb(93%,91%,67%)",
"rgba(93%,91%,67%,1)",
"rgba(93%,91%,67%,100%)",
"hsl(55,67%,80%)",
"hsla(55,67%,80%,1)",
"hsla(55,67%,80%,100%)",
"hwb(55,67%,7%)",
"hwb(55,67%,7%,1)",
"hwb(55,67%,7%,100%)",
],
},
"palegreen": {
"hex": [
"#98fb98", "#ff98fb98",
],
"func": [
"rgb(152,251,152)",
"rgba(152,251,152,1)",
"rgba(152,251,152,100%)",
"rgb(60%,98%,60%)",
"rgba(60%,98%,60%,1)",
"rgba(60%,98%,60%,100%)",
"hsl(120,93%,79%)",
"hsla(120,93%,79%,1)",
"hsla(120,93%,79%,100%)",
"hwb(120,60%,2%)",
"hwb(120,60%,2%,1)",
"hwb(120,60%,2%,100%)",
],
},
"paleturquoise": {
"hex": [
"#afeeee", "#ffafeeee",
],
"func": [
"rgb(175,238,238)",
"rgba(175,238,238,1)",
"rgba(175,238,238,100%)",
"rgb(69%,93%,93%)",
"rgba(69%,93%,93%,1)",
"rgba(69%,93%,93%,100%)",
"hsl(180,65%,81%)",
"hsla(180,65%,81%,1)",
"hsla(180,65%,81%,100%)",
"hwb(180,69%,7%)",
"hwb(180,69%,7%,1)",
"hwb(180,69%,7%,100%)",
],
},
"palevioletred": {
"hex": [
"#db7093", "#ffdb7093",
],
"func": [
"rgb(219,112,147)",
"rgba(219,112,147,1)",
"rgba(219,112,147,100%)",
"rgb(86%,44%,58%)",
"rgba(86%,44%,58%,1)",
"rgba(86%,44%,58%,100%)",
"hsl(340,60%,65%)",
"hsla(340,60%,65%,1)",
"hsla(340,60%,65%,100%)",
"hwb(340,44%,14%)",
"hwb(340,44%,14%,1)",
"hwb(340,44%,14%,100%)",
],
},
"papayawhip": {
"hex": [
"#ffefd5", "#ffffefd5",
],
"func": [
"rgb(255,239,213)",
"rgba(255,239,213,1)",
"rgba(255,239,213,100%)",
"rgb(100%,94%,84%)",
"rgba(100%,94%,84%,1)",
"rgba(100%,94%,84%,100%)",
"hsl(37,100%,92%)",
"hsla(37,100%,92%,1)",
"hsla(37,100%,92%,100%)",
"hwb(37,84%,0%)",
"hwb(37,84%,0%,1)",
"hwb(37,84%,0%,100%)",
],
},
"peachpuff": {
"hex": [
"#ffdab9", "#ffffdab9",
],
"func": [
"rgb(255,218,185)",
"rgba(255,218,185,1)",
"rgba(255,218,185,100%)",
"rgb(100%,85%,73%)",
"rgba(100%,85%,73%,1)",
"rgba(100%,85%,73%,100%)",
"hsl(28,100%,86%)",
"hsla(28,100%,86%,1)",
"hsla(28,100%,86%,100%)",
"hwb(28,73%,0%)",
"hwb(28,73%,0%,1)",
"hwb(28,73%,0%,100%)",
],
},
"peru": {
"hex": [
"#cd853f", "#ffcd853f",
],
"func": [
"rgb(205,133,63)",
"rgba(205,133,63,1)",
"rgba(205,133,63,100%)",
"rgb(80%,52%,25%)",
"rgba(80%,52%,25%,1)",
"rgba(80%,52%,25%,100%)",
"hsl(30,59%,53%)",
"hsla(30,59%,53%,1)",
"hsla(30,59%,53%,100%)",
"hwb(30,25%,20%)",
"hwb(30,25%,20%,1)",
"hwb(30,25%,20%,100%)",
],
},
"pink": {
"hex": [
"#ffc0cb", "#ffffc0cb",
],
"func": [
"rgb(255,192,203)",
"rgba(255,192,203,1)",
"rgba(255,192,203,100%)",
"rgb(100%,75%,80%)",
"rgba(100%,75%,80%,1)",
"rgba(100%,75%,80%,100%)",
"hsl(350,100%,88%)",
"hsla(350,100%,88%,1)",
"hsla(350,100%,88%,100%)",
"hwb(350,75%,0%)",
"hwb(350,75%,0%,1)",
"hwb(350,75%,0%,100%)",
],
},
"plum": {
"hex": [
"#dda0dd", "#ffdda0dd",
],
"func": [
"rgb(221,160,221)",
"rgba(221,160,221,1)",
"rgba(221,160,221,100%)",
"rgb(87%,63%,87%)",
"rgba(87%,63%,87%,1)",
"rgba(87%,63%,87%,100%)",
"hsl(300,47%,75%)",
"hsla(300,47%,75%,1)",
"hsla(300,47%,75%,100%)",
"hwb(300,63%,13%)",
"hwb(300,63%,13%,1)",
"hwb(300,63%,13%,100%)",
],
},
"powderblue": {
"hex": [
"#b0e0e6", "#ffb0e0e6",
],
"func": [
"rgb(176,224,230)",
"rgba(176,224,230,1)",
"rgba(176,224,230,100%)",
"rgb(69%,88%,90%)",
"rgba(69%,88%,90%,1)",
"rgba(69%,88%,90%,100%)",
"hsl(187,52%,80%)",
"hsla(187,52%,80%,1)",
"hsla(187,52%,80%,100%)",
"hwb(187,69%,10%)",
"hwb(187,69%,10%,1)",
"hwb(187,69%,10%,100%)",
],
},
"purple": {
"hex": [
"#800080", "#ff800080",
],
"func": [
"rgb(128,0,128)",
"rgba(128,0,128,1)",
"rgba(128,0,128,100%)",
"rgb(50%,0%,50%)",
"rgba(50%,0%,50%,1)",
"rgba(50%,0%,50%,100%)",
"hsl(300,100%,25%)",
"hsla(300,100%,25%,1)",
"hsla(300,100%,25%,100%)",
"hwb(300,0%,50%)",
"hwb(300,0%,50%,1)",
"hwb(300,0%,50%,100%)",
],
},
"rebeccapurple": {
"hex": [
"#663399", "#ff663399", "#639", "#f639",
],
"func": [
"rgb(102,51,153)",
"rgba(102,51,153,1)",
"rgba(102,51,153,100%)",
"rgb(40%,20%,60%)",
"rgba(40%,20%,60%,1)",
"rgba(40%,20%,60%,100%)",
"hsl(270,50%,40%)",
"hsla(270,50%,40%,1)",
"hsla(270,50%,40%,100%)",
"hwb(270,20%,40%)",
"hwb(270,20%,40%,1)",
"hwb(270,20%,40%,100%)",
],
},
"red": {
"hex": [
"#ff0000", "#ffff0000", "#f00", "#ff00",
],
"func": [
"rgb(255,0,0)",
"rgba(255,0,0,1)",
"rgba(255,0,0,100%)",
"rgb(100%,0%,0%)",
"rgba(100%,0%,0%,1)",
"rgba(100%,0%,0%,100%)",
"hsl(0,100%,50%)",
"hsla(0,100%,50%,1)",
"hsla(0,100%,50%,100%)",
"hwb(0,0%,0%)",
"hwb(0,0%,0%,1)",
"hwb(0,0%,0%,100%)",
],
},
"rosybrown": {
"hex": [
"#bc8f8f", "#ffbc8f8f",
],
"func": [
"rgb(188,143,143)",
"rgba(188,143,143,1)",
"rgba(188,143,143,100%)",
"rgb(74%,56%,56%)",
"rgba(74%,56%,56%,1)",
"rgba(74%,56%,56%,100%)",
"hsl(0,25%,65%)",
"hsla(0,25%,65%,1)",
"hsla(0,25%,65%,100%)",
"hwb(0,56%,26%)",
"hwb(0,56%,26%,1)",
"hwb(0,56%,26%,100%)",
],
},
"royalblue": {
"hex": [
"#4169e1", "#ff4169e1",
],
"func": [
"rgb(65,105,225)",
"rgba(65,105,225,1)",
"rgba(65,105,225,100%)",
"rgb(25%,41%,88%)",
"rgba(25%,41%,88%,1)",
"rgba(25%,41%,88%,100%)",
"hsl(225,73%,57%)",
"hsla(225,73%,57%,1)",
"hsla(225,73%,57%,100%)",
"hwb(225,25%,12%)",
"hwb(225,25%,12%,1)",
"hwb(225,25%,12%,100%)",
],
},
"saddlebrown": {
"hex": [
"#8b4513", "#ff8b4513",
],
"func": [
"rgb(139,69,19)",
"rgba(139,69,19,1)",
"rgba(139,69,19,100%)",
"rgb(55%,27%,7%)",
"rgba(55%,27%,7%,1)",
"rgba(55%,27%,7%,100%)",
"hsl(25,76%,31%)",
"hsla(25,76%,31%,1)",
"hsla(25,76%,31%,100%)",
"hwb(25,7%,45%)",
"hwb(25,7%,45%,1)",
"hwb(25,7%,45%,100%)",
],
},
"salmon": {
"hex": [
"#fa8072", "#fffa8072",
],
"func": [
"rgb(250,128,114)",
"rgba(250,128,114,1)",
"rgba(250,128,114,100%)",
"rgb(98%,50%,45%)",
"rgba(98%,50%,45%,1)",
"rgba(98%,50%,45%,100%)",
"hsl(6,93%,71%)",
"hsla(6,93%,71%,1)",
"hsla(6,93%,71%,100%)",
"hwb(6,45%,2%)",
"hwb(6,45%,2%,1)",
"hwb(6,45%,2%,100%)",
],
},
"sandybrown": {
"hex": [
"#f4a460", "#fff4a460",
],
"func": [
"rgb(244,164,96)",
"rgba(244,164,96,1)",
"rgba(244,164,96,100%)",
"rgb(96%,64%,38%)",
"rgba(96%,64%,38%,1)",
"rgba(96%,64%,38%,100%)",
"hsl(28,87%,67%)",
"hsla(28,87%,67%,1)",
"hsla(28,87%,67%,100%)",
"hwb(28,38%,4%)",
"hwb(28,38%,4%,1)",
"hwb(28,38%,4%,100%)",
],
},
"seagreen": {
"hex": [
"#2e8b57", "#ff2e8b57",
],
"func": [
"rgb(46,139,87)",
"rgba(46,139,87,1)",
"rgba(46,139,87,100%)",
"rgb(18%,55%,34%)",
"rgba(18%,55%,34%,1)",
"rgba(18%,55%,34%,100%)",
"hsl(146,50%,36%)",
"hsla(146,50%,36%,1)",
"hsla(146,50%,36%,100%)",
"hwb(146,18%,45%)",
"hwb(146,18%,45%,1)",
"hwb(146,18%,45%,100%)",
],
},
"seashell": {
"hex": [
"#fff5ee", "#fffff5ee",
],
"func": [
"rgb(255,245,238)",
"rgba(255,245,238,1)",
"rgba(255,245,238,100%)",
"rgb(100%,96%,93%)",
"rgba(100%,96%,93%,1)",
"rgba(100%,96%,93%,100%)",
"hsl(25,100%,97%)",
"hsla(25,100%,97%,1)",
"hsla(25,100%,97%,100%)",
"hwb(25,93%,0%)",
"hwb(25,93%,0%,1)",
"hwb(25,93%,0%,100%)",
],
},
"sienna": {
"hex": [
"#a0522d", "#ffa0522d",
],
"func": [
"rgb(160,82,45)",
"rgba(160,82,45,1)",
"rgba(160,82,45,100%)",
"rgb(63%,32%,18%)",
"rgba(63%,32%,18%,1)",
"rgba(63%,32%,18%,100%)",
"hsl(19,56%,40%)",
"hsla(19,56%,40%,1)",
"hsla(19,56%,40%,100%)",
"hwb(19,18%,37%)",
"hwb(19,18%,37%,1)",
"hwb(19,18%,37%,100%)",
],
},
"silver": {
"hex": [
"#c0c0c0", "#ffc0c0c0",
],
"func": [
"rgb(192,192,192)",
"rgba(192,192,192,1)",
"rgba(192,192,192,100%)",
"rgb(75%,75%,75%)",
"rgba(75%,75%,75%,1)",
"rgba(75%,75%,75%,100%)",
"hsl(0,0%,75%)",
"hsla(0,0%,75%,1)",
"hsla(0,0%,75%,100%)",
"hwb(0,75%,25%)",
"hwb(0,75%,25%,1)",
"hwb(0,75%,25%,100%)",
],
},
"skyblue": {
"hex": [
"#87ceeb", "#ff87ceeb",
],
"func": [
"rgb(135,206,235)",
"rgba(135,206,235,1)",
"rgba(135,206,235,100%)",
"rgb(53%,81%,92%)",
"rgba(53%,81%,92%,1)",
"rgba(53%,81%,92%,100%)",
"hsl(197,71%,73%)",
"hsla(197,71%,73%,1)",
"hsla(197,71%,73%,100%)",
"hwb(197,53%,8%)",
"hwb(197,53%,8%,1)",
"hwb(197,53%,8%,100%)",
],
},
"slateblue": {
"hex": [
"#6a5acd", "#ff6a5acd",
],
"func": [
"rgb(106,90,205)",
"rgba(106,90,205,1)",
"rgba(106,90,205,100%)",
"rgb(42%,35%,80%)",
"rgba(42%,35%,80%,1)",
"rgba(42%,35%,80%,100%)",
"hsl(248,53%,58%)",
"hsla(248,53%,58%,1)",
"hsla(248,53%,58%,100%)",
"hwb(248,35%,20%)",
"hwb(248,35%,20%,1)",
"hwb(248,35%,20%,100%)",
],
},
"slategray": {
"hex": [
"#708090", "#ff708090",
],
"func": [
"rgb(112,128,144)",
"rgba(112,128,144,1)",
"rgba(112,128,144,100%)",
"rgb(44%,50%,56%)",
"rgba(44%,50%,56%,1)",
"rgba(44%,50%,56%,100%)",
"hsl(210,13%,50%)",
"hsla(210,13%,50%,1)",
"hsla(210,13%,50%,100%)",
"hwb(210,44%,44%)",
"hwb(210,44%,44%,1)",
"hwb(210,44%,44%,100%)",
],
},
"slategrey": {
"hex": [
"#708090", "#ff708090",
],
"func": [
"rgb(112,128,144)",
"rgba(112,128,144,1)",
"rgba(112,128,144,100%)",
"rgb(44%,50%,56%)",
"rgba(44%,50%,56%,1)",
"rgba(44%,50%,56%,100%)",
"hsl(210,13%,50%)",
"hsla(210,13%,50%,1)",
"hsla(210,13%,50%,100%)",
"hwb(210,44%,44%)",
"hwb(210,44%,44%,1)",
"hwb(210,44%,44%,100%)",
],
},
"snow": {
"hex": [
"#fffafa", "#fffffafa",
],
"func": [
"rgb(255,250,250)",
"rgba(255,250,250,1)",
"rgba(255,250,250,100%)",
"rgb(100%,98%,98%)",
"rgba(100%,98%,98%,1)",
"rgba(100%,98%,98%,100%)",
"hsl(0,100%,99%)",
"hsla(0,100%,99%,1)",
"hsla(0,100%,99%,100%)",
"hwb(0,98%,0%)",
"hwb(0,98%,0%,1)",
"hwb(0,98%,0%,100%)",
],
},
"springgreen": {
"hex": [
"#00ff7f", "#ff00ff7f",
],
"func": [
"rgb(0,255,127)",
"rgba(0,255,127,1)",
"rgba(0,255,127,100%)",
"rgb(0%,100%,50%)",
"rgba(0%,100%,50%,1)",
"rgba(0%,100%,50%,100%)",
"hsl(150,100%,50%)",
"hsla(150,100%,50%,1)",
"hsla(150,100%,50%,100%)",
"hwb(150,0%,0%)",
"hwb(150,0%,0%,1)",
"hwb(150,0%,0%,100%)",
],
},
"steelblue": {
"hex": [
"#4682b4", "#ff4682b4",
],
"func": [
"rgb(70,130,180)",
"rgba(70,130,180,1)",
"rgba(70,130,180,100%)",
"rgb(27%,51%,71%)",
"rgba(27%,51%,71%,1)",
"rgba(27%,51%,71%,100%)",
"hsl(207,44%,49%)",
"hsla(207,44%,49%,1)",
"hsla(207,44%,49%,100%)",
"hwb(207,27%,29%)",
"hwb(207,27%,29%,1)",
"hwb(207,27%,29%,100%)",
],
},
"tan": {
"hex": [
"#d2b48c", "#ffd2b48c",
],
"func": [
"rgb(210,180,140)",
"rgba(210,180,140,1)",
"rgba(210,180,140,100%)",
"rgb(82%,71%,55%)",
"rgba(82%,71%,55%,1)",
"rgba(82%,71%,55%,100%)",
"hsl(34,44%,69%)",
"hsla(34,44%,69%,1)",
"hsla(34,44%,69%,100%)",
"hwb(34,55%,18%)",
"hwb(34,55%,18%,1)",
"hwb(34,55%,18%,100%)",
],
},
"teal": {
"hex": [
"#008080", "#ff008080",
],
"func": [
"rgb(0,128,128)",
"rgba(0,128,128,1)",
"rgba(0,128,128,100%)",
"rgb(0%,50%,50%)",
"rgba(0%,50%,50%,1)",
"rgba(0%,50%,50%,100%)",
"hsl(180,100%,25%)",
"hsla(180,100%,25%,1)",
"hsla(180,100%,25%,100%)",
"hwb(180,0%,50%)",
"hwb(180,0%,50%,1)",
"hwb(180,0%,50%,100%)",
],
},
"thistle": {
"hex": [
"#d8bfd8", "#ffd8bfd8",
],
"func": [
"rgb(216,191,216)",
"rgba(216,191,216,1)",
"rgba(216,191,216,100%)",
"rgb(85%,75%,85%)",
"rgba(85%,75%,85%,1)",
"rgba(85%,75%,85%,100%)",
"hsl(300,24%,80%)",
"hsla(300,24%,80%,1)",
"hsla(300,24%,80%,100%)",
"hwb(300,75%,15%)",
"hwb(300,75%,15%,1)",
"hwb(300,75%,15%,100%)",
],
},
"tomato": {
"hex": [
"#ff6347", "#ffff6347",
],
"func": [
"rgb(255,99,71)",
"rgba(255,99,71,1)",
"rgba(255,99,71,100%)",
"rgb(100%,39%,28%)",
"rgba(100%,39%,28%,1)",
"rgba(100%,39%,28%,100%)",
"hsl(9,100%,64%)",
"hsla(9,100%,64%,1)",
"hsla(9,100%,64%,100%)",
"hwb(9,28%,0%)",
"hwb(9,28%,0%,1)",
"hwb(9,28%,0%,100%)",
],
},
"turquoise": {
"hex": [
"#40e0d0", "#ff40e0d0",
],
"func": [
"rgb(64,224,208)",
"rgba(64,224,208,1)",
"rgba(64,224,208,100%)",
"rgb(25%,88%,82%)",
"rgba(25%,88%,82%,1)",
"rgba(25%,88%,82%,100%)",
"hsl(174,72%,56%)",
"hsla(174,72%,56%,1)",
"hsla(174,72%,56%,100%)",
"hwb(174,25%,12%)",
"hwb(174,25%,12%,1)",
"hwb(174,25%,12%,100%)",
],
},
"violet": {
"hex": [
"#ee82ee", "#ffee82ee",
],
"func": [
"rgb(238,130,238)",
"rgba(238,130,238,1)",
"rgba(238,130,238,100%)",
"rgb(93%,51%,93%)",
"rgba(93%,51%,93%,1)",
"rgba(93%,51%,93%,100%)",
"hsl(300,76%,72%)",
"hsla(300,76%,72%,1)",
"hsla(300,76%,72%,100%)",
"hwb(300,51%,7%)",
"hwb(300,51%,7%,1)",
"hwb(300,51%,7%,100%)",
],
},
"wheat": {
"hex": [
"#f5deb3", "#fff5deb3",
],
"func": [
"rgb(245,222,179)",
"rgba(245,222,179,1)",
"rgba(245,222,179,100%)",
"rgb(96%,87%,70%)",
"rgba(96%,87%,70%,1)",
"rgba(96%,87%,70%,100%)",
"hsl(39,77%,83%)",
"hsla(39,77%,83%,1)",
"hsla(39,77%,83%,100%)",
"hwb(39,70%,4%)",
"hwb(39,70%,4%,1)",
"hwb(39,70%,4%,100%)",
],
},
"white": {
"hex": [
"#ffffff", "#ffffffff", "#fff", "#ffff",
],
"func": [
"rgb(255,255,255)",
"rgba(255,255,255,1)",
"rgba(255,255,255,100%)",
"rgb(100%,100%,100%)",
"rgba(100%,100%,100%,1)",
"rgba(100%,100%,100%,100%)",
"hsl(0,0%,100%)",
"hsla(0,0%,100%,1)",
"hsla(0,0%,100%,100%)",
"hwb(0,100%,0%)",
"hwb(0,100%,0%,1)",
"hwb(0,100%,0%,100%)",
"gray(255)",
"gray(255,1)",
"gray(255,100%)",
"gray(255%)",
"gray(255%,1)",
"gray(255%,100%)",
],
},
"whitesmoke": {
"hex": [
"#f5f5f5", "#fff5f5f5",
],
"func": [
"rgb(245,245,245)",
"rgba(245,245,245,1)",
"rgba(245,245,245,100%)",
"rgb(96%,96%,96%)",
"rgba(96%,96%,96%,1)",
"rgba(96%,96%,96%,100%)",
"hsl(0,0%,96%)",
"hsla(0,0%,96%,1)",
"hsla(0,0%,96%,100%)",
"hwb(0,96%,4%)",
"hwb(0,96%,4%,1)",
"hwb(0,96%,4%,100%)",
"gray(245)",
"gray(245,1)",
"gray(245,100%)",
"gray(245%)",
"gray(245%,1)",
"gray(245%,100%)",
],
},
"yellow": {
"hex": [
"#ffff00", "#ffffff00", "#ff0", "#fff0",
],
"func": [
"rgb(255,255,0)",
"rgba(255,255,0,1)",
"rgba(255,255,0,100%)",
"rgb(100%,100%,0%)",
"rgba(100%,100%,0%,1)",
"rgba(100%,100%,0%,100%)",
"hsl(60,100%,50%)",
"hsla(60,100%,50%,1)",
"hsla(60,100%,50%,100%)",
"hwb(60,0%,0%)",
"hwb(60,0%,0%,1)",
"hwb(60,0%,0%,100%)",
],
},
"yellowgreen": {
"hex": [
"#9acd32", "#ff9acd32",
],
"func": [
"rgb(154,205,50)",
"rgba(154,205,50,1)",
"rgba(154,205,50,100%)",
"rgb(60%,80%,20%)",
"rgba(60%,80%,20%,1)",
"rgba(60%,80%,20%,100%)",
"hsl(80,61%,50%)",
"hsla(80,61%,50%,1)",
"hsla(80,61%,50%,100%)",
"hwb(80,20%,20%)",
"hwb(80,20%,20%,1)",
"hwb(80,20%,20%,100%)",
],
},
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 1 1 1 | "use strict"
const propertySets = {}
propertySets.acceptCustomIdents = new Set([
"animation",
"animation-name",
"font",
"font-family",
"counter-increment",
"grid-row",
"grid-column",
"grid-area",
"list-style",
"list-style-type",
])
module.exports = propertySets
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 1 1 1 1 | "use strict"
const punctuationSets = {}
punctuationSets.mediaFeaturePunctuation = new Set([
":",
"=",
">",
">=",
"<",
"<=",
])
punctuationSets.nonSpaceCombinators = new Set([
">",
"+",
"~",
])
module.exports = punctuationSets
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | 1 | "use strict"
module.exports = {
"margin": [
"margin-top",
"margin-bottom",
"margin-left",
"margin-right",
],
"padding": [
"padding-top",
"padding-bottom",
"padding-left",
"padding-right",
],
"background": [
"background-image",
"background-size",
"background-position",
"background-repeat",
"background-origin",
"background-clip",
"background-attachment",
"background-color",
],
"font": [
"font-style",
"font-variant",
"font-weight",
"font-stretch",
"font-size",
"font-family",
"line-height",
],
"border": [
"border-top-width",
"border-bottom-width",
"border-left-width",
"border-right-width",
"border-top-style",
"border-bottom-style",
"border-left-style",
"border-right-style",
"border-top-color",
"border-bottom-color",
"border-left-color",
"border-right-color",
],
"border-top": [
"border-top-width",
"border-top-style",
"border-top-color",
],
"border-bottom": [
"border-bottom-width",
"border-bottom-style",
"border-bottom-color",
],
"border-left": [
"border-left-width",
"border-left-style",
"border-left-color",
],
"border-right": [
"border-right-width",
"border-right-style",
"border-right-color",
],
"border-width": [
"border-top-width",
"border-bottom-width",
"border-left-width",
"border-right-width",
],
"border-style": [
"border-top-style",
"border-bottom-style",
"border-left-style",
"border-right-style",
],
"border-color": [
"border-top-color",
"border-bottom-color",
"border-left-color",
"border-right-color",
],
"list-style": [
"list-style-type",
"list-style-position",
"list-style-image",
],
"border-radius": [
"border-top-right-radius",
"border-top-left-radius",
"border-bottom-right-radius",
"border-bottom-left-radius",
],
"transition": [
"transition-delay",
"transition-duration",
"transition-property",
"transition-timing-function",
],
"-webkit-transition": [
"-webkit-transition-delay",
"-webkit-transition-duration",
"-webkit-transition-property",
"-webkit-transition-timing-function",
],
"-moz-transition": [
"-moz-transition-delay",
"-moz-transition-duration",
"-moz-transition-property",
"-moz-transition-timing-function",
],
"-o-transition": [ "-o-transition-delay",
"-o-transition-duration",
"-o-transition-property",
"-o-transition-timing-function" ],
}
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| atRuleNameSpaceChecker.js | 40% | (4 / 10) | 0% | (0 / 4) | 0% | (0 / 2) | 40% | (4 / 10) | |
| checkRuleEmptyLineBefore.js | 23.81% | (5 / 21) | 0% | (0 / 30) | 0% | (0 / 1) | 23.81% | (5 / 21) | |
| declarationBangSpaceChecker.js | 33.33% | (5 / 15) | 0% | (0 / 2) | 0% | (0 / 3) | 35.71% | (5 / 14) | |
| declarationColonSpaceChecker.js | 26.67% | (4 / 15) | 0% | (0 / 6) | 0% | (0 / 1) | 26.67% | (4 / 15) | |
| findMediaOperator.js | 25% | (2 / 8) | 0% | (0 / 2) | 0% | (0 / 1) | 25% | (2 / 8) | |
| functionCommaSpaceChecker.js | 26.92% | (7 / 26) | 0% | (0 / 6) | 0% | (0 / 1) | 26.92% | (7 / 26) | |
| index.js | 100% | (176 / 176) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (176 / 176) | |
| mediaFeatureColonSpaceChecker.js | 45.45% | (5 / 11) | 100% | (0 / 0) | 0% | (0 / 2) | 50% | (5 / 10) | |
| mediaQueryListCommaWhitespaceChecker.js | 45.45% | (5 / 11) | 100% | (0 / 0) | 0% | (0 / 2) | 50% | (5 / 10) | |
| selectorAttributeOperatorSpaceChecker.js | 27.27% | (6 / 22) | 0% | (0 / 12) | 0% | (0 / 2) | 27.27% | (6 / 22) | |
| selectorCombinatorSpaceChecker.js | 35.29% | (6 / 17) | 0% | (0 / 6) | 0% | (0 / 2) | 37.5% | (6 / 16) | |
| selectorListCommaWhitespaceChecker.js | 38.46% | (5 / 13) | 0% | (0 / 2) | 0% | (0 / 2) | 41.67% | (5 / 12) | |
| valueListCommaWhitespaceChecker.js | 46.15% | (6 / 13) | 0% | (0 / 4) | 0% | (0 / 2) | 46.15% | (6 / 13) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 1 1 1 1 | "use strict"
const isStandardSyntaxAtRule = require("../utils/isStandardSyntaxAtRule")
const report = require("../utils/report")
module.exports = function (options) {
options.root.walkAtRules(atRule => {
if (!isStandardSyntaxAtRule(atRule)) {
return
}
checkColon(`@${atRule.name}${(atRule.raws.afterName || "")}${atRule.params}`, atRule.name.length, atRule)
})
function checkColon(source, index, node) {
options.locationChecker({
source,
index,
err: m => report({
message: m,
node,
index,
result: options.result,
ruleName: options.checkedRuleName,
}),
errTarget: `@${node.name}`,
})
}
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 1 1 1 1 1 | "use strict"
const hasEmptyLine = require("../utils/hasEmptyLine")
const isSingleLineString = require("../utils/isSingleLineString")
const optionsMatches = require("../utils/optionsMatches")
const report = require("../utils/report")
module.exports = function (opts) {
let expectEmptyLineBefore = opts.expectation.indexOf("always") !== -1 ? true : false
// Optionally ignore the expectation if a comment precedes this node
if (optionsMatches(opts.options, "ignore", "after-comment") && opts.rule.prev() && opts.rule.prev().type === "comment") {
return
}
// Ignore if the expectation is for multiple and the rule is single-line
if (opts.expectation.indexOf("multi-line") !== -1 && isSingleLineString(opts.rule.toString())) {
return
}
// Optionally reverse the expectation for the first nested node
if (optionsMatches(opts.options, "except", "first-nested") && opts.rule === opts.rule.parent.first) {
expectEmptyLineBefore = !expectEmptyLineBefore
}
// Optionally reverse the expectation if a rule precedes this node
if (optionsMatches(opts.options, "except", "after-rule") && opts.rule.prev() && opts.rule.prev().type === "rule") {
expectEmptyLineBefore = !expectEmptyLineBefore
}
// Optionally reverse the expectation for single line comments
if (optionsMatches(opts.options, "except", "after-single-line-comment") && opts.rule.prev() && opts.rule.prev().type === "comment" && isSingleLineString(opts.rule.prev().toString())) {
expectEmptyLineBefore = !expectEmptyLineBefore
}
const hasEmptyLineBefore = hasEmptyLine(opts.rule.raws.before)
// Return if the expectation is met
if (expectEmptyLineBefore === hasEmptyLineBefore) {
return
}
const message = expectEmptyLineBefore ? opts.messages.expected : opts.messages.rejected
report({
message,
node: opts.rule,
result: opts.result,
ruleName: opts.checkedRuleName,
})
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 1 1 1 1 1 | "use strict"
const declarationValueIndex = require("../utils/declarationValueIndex")
const report = require("../utils/report")
const styleSearch = require("style-search")
module.exports = function (opts) {
opts.root.walkDecls(function (decl) {
const indexOffset = declarationValueIndex(decl)
const declString = decl.toString()
const valueString = decl.toString().slice(indexOffset)
if (valueString.indexOf("!") == -1) {
return
}
styleSearch({ source: valueString, target: "!" }, match => {
check(declString, match.startIndex + indexOffset, decl)
})
})
function check(source, index, node) {
opts.locationChecker({ source, index, err: m => report({
message: m,
node,
index,
result: opts.result,
ruleName: opts.checkedRuleName,
}),
})
}
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 1 1 1 1 | "use strict"
const declarationValueIndex = require("../utils/declarationValueIndex")
const isStandardSyntaxDeclaration = require("../utils/isStandardSyntaxDeclaration")
const report = require("../utils/report")
module.exports = function (opts) {
opts.root.walkDecls(decl => {
if (!isStandardSyntaxDeclaration(decl)) {
return
}
// Get the raw prop, and only the prop
const endOfPropIndex = declarationValueIndex(decl) + (decl.raws.between || "").length - 1
// The extra characters tacked onto the end ensure that there is a character to check
// after the colon. Otherwise, with `background:pink` the character after the
const propPlusColon = decl.toString().slice(0, endOfPropIndex) + "xxx"
for (let i = 0, l = propPlusColon.length; i < l; i++) {
if (propPlusColon[i] !== ":") {
continue
}
opts.locationChecker({
source: propPlusColon,
index: i,
lineCheckStr: decl.value,
err: m => {
report({
message: m,
node: decl,
index: decl.prop.toString().length + 1,
result: opts.result,
ruleName: opts.checkedRuleName,
})
},
})
break
}
})
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 1 1 | "use strict" const rangeOperatorRegex = /[^><](>=?|<=?|=)/g module.exports = function (atRule, cb) { if (atRule.name.toLowerCase() !== "media") { return } const params = atRule.params let match while ((match = rangeOperatorRegex.exec(params)) !== null) { cb(match, params, atRule) } } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | 1 1 1 1 1 1 1 | "use strict"
const declarationValueIndex = require("../utils/declarationValueIndex")
const isStandardSyntaxFunction = require("../utils/isStandardSyntaxFunction")
const report = require("../utils/report")
const _ = require("lodash")
const styleSearch = require("style-search")
const valueParser = require("postcss-value-parser")
module.exports = function (opts) {
opts.root.walkDecls(decl => {
const declValue = _.get(decl, "raws.value.raw", decl.value)
valueParser(declValue).walk(valueNode => {
if (valueNode.type !== "function") {
return
}
if (!isStandardSyntaxFunction(valueNode)) {
return
}
// Ignore `url()` arguments, which may contain data URIs or other funky stuff
if (valueNode.value.toLowerCase() === "url") {
return
}
const functionArguments = (() => {
let result = valueParser.stringify(valueNode)
// Remove function name and opening paren
result = result.slice(valueNode.value.length + 1)
// Remove closing paren
result = result.slice(0, result.length - 1)
// 1. Remove comments including preceeding whitespace (when only succeeded by whitespace)
// 2. Remove all other comments, but leave adjacent whitespace intact
result = result.replace(/(\ *\/(\*.*\*\/(?!\S)|\/.*)|(\/(\*.*\*\/|\/.*)))/, "")
return result
})()
styleSearch({
source: functionArguments,
target: ",",
functionArguments: "skip",
}, match => {
opts.locationChecker({
source: functionArguments,
index: match.startIndex,
err: message => {
const index = declarationValueIndex(decl) + valueNode.value.length + 1 + valueNode.sourceIndex + match.startIndex
report({
index,
message,
node: decl,
result: opts.result,
ruleName: opts.checkedRuleName,
})
},
})
})
})
})
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleBlacklist = require("./at-rule-blacklist")
const atRuleEmptyLineBefore = require("./at-rule-empty-line-before")
const atRuleNameCase = require("./at-rule-name-case")
const atRuleNameNewlineAfter = require("./at-rule-name-newline-after")
const atRuleSemicolonSpaceBefore = require("./at-rule-semicolon-space-before")
const atRuleNameSpaceAfter = require("./at-rule-name-space-after")
const atRuleNoUnknown = require("./at-rule-no-unknown")
const atRuleNoVendorPrefix = require("./at-rule-no-vendor-prefix")
const atRuleSemicolonNewlineAfter = require("./at-rule-semicolon-newline-after")
const atRuleWhitelist = require("./at-rule-whitelist")
const blockClosingBraceEmptyLineBefore = require("./block-closing-brace-empty-line-before")
const blockClosingBraceNewlineAfter = require("./block-closing-brace-newline-after")
const blockClosingBraceNewlineBefore = require("./block-closing-brace-newline-before")
const blockClosingBraceSpaceAfter = require("./block-closing-brace-space-after")
const blockClosingBraceSpaceBefore = require("./block-closing-brace-space-before")
const blockNoEmpty = require("./block-no-empty")
const blockNoSingleLine = require("./block-no-single-line")
const blockOpeningBraceNewlineAfter = require("./block-opening-brace-newline-after")
const blockOpeningBraceNewlineBefore = require("./block-opening-brace-newline-before")
const blockOpeningBraceSpaceAfter = require("./block-opening-brace-space-after")
const blockOpeningBraceSpaceBefore = require("./block-opening-brace-space-before")
const colorHexCase = require("./color-hex-case")
const colorHexLength = require("./color-hex-length")
const colorNamed = require("./color-named")
const colorNoHex = require("./color-no-hex")
const colorNoInvalidHex = require("./color-no-invalid-hex")
const commentEmptyLineBefore = require("./comment-empty-line-before")
const commentNoEmpty = require("./comment-no-empty")
const commentWhitespaceInside = require("./comment-whitespace-inside")
const commentWordBlacklist = require("./comment-word-blacklist")
const customMediaPattern = require("./custom-media-pattern")
const customPropertyEmptyLineBefore = require("./custom-property-empty-line-before")
const customPropertyNoOutsideRoot = require("./custom-property-no-outside-root")
const customPropertyPattern = require("./custom-property-pattern")
const declarationBangSpaceAfter = require("./declaration-bang-space-after")
const declarationBangSpaceBefore = require("./declaration-bang-space-before")
const declarationBlockNoDuplicateProperties = require("./declaration-block-no-duplicate-properties")
const declarationBlockNoIgnoredProperties = require("./declaration-block-no-ignored-properties")
const declarationBlockNoRedundantLonghandProperties = require("./declaration-block-no-redundant-longhand-properties")
const declarationBlockNoShorthandPropertyOverrides = require("./declaration-block-no-shorthand-property-overrides")
const declarationBlockPropertiesOrder = require("./declaration-block-properties-order")
const declarationBlockSemicolonNewlineAfter = require("./declaration-block-semicolon-newline-after")
const declarationBlockSemicolonNewlineBefore = require("./declaration-block-semicolon-newline-before")
const declarationBlockSemicolonSpaceAfter = require("./declaration-block-semicolon-space-after")
const declarationBlockSemicolonSpaceBefore = require("./declaration-block-semicolon-space-before")
const declarationBlockSingleLineMaxDeclarations = require("./declaration-block-single-line-max-declarations")
const declarationBlockTrailingSemicolon = require("./declaration-block-trailing-semicolon")
const declarationColonNewlineAfter = require("./declaration-colon-newline-after")
const declarationColonSpaceAfter = require("./declaration-colon-space-after")
const declarationColonSpaceBefore = require("./declaration-colon-space-before")
const declarationEmptyLineBefore = require("./declaration-empty-line-before")
const declarationNoImportant = require("./declaration-no-important")
const declarationPropertyUnitBlacklist = require("./declaration-property-unit-blacklist")
const declarationPropertyUnitWhitelist = require("./declaration-property-unit-whitelist")
const declarationPropertyValueBlacklist = require("./declaration-property-value-blacklist")
const declarationPropertyValueWhitelist = require("./declaration-property-value-whitelist")
const fontFamilyNameQuotes = require("./font-family-name-quotes")
const fontFamilyNoDuplicateNames = require("./font-family-no-duplicate-names")
const fontWeightNotation = require("./font-weight-notation")
const functionBlacklist = require("./function-blacklist")
const functionCalcNoUnspacedOperator = require("./function-calc-no-unspaced-operator")
const functionCommaNewlineAfter = require("./function-comma-newline-after")
const functionCommaNewlineBefore = require("./function-comma-newline-before")
const functionCommaSpaceAfter = require("./function-comma-space-after")
const functionCommaSpaceBefore = require("./function-comma-space-before")
const functionLinearGradientNoNonstandardDirection = require("./function-linear-gradient-no-nonstandard-direction")
const functionMaxEmptyLines = require("./function-max-empty-lines")
const functionNameCase = require("./function-name-case")
const functionParenthesesNewlineInside = require("./function-parentheses-newline-inside")
const functionParenthesesSpaceInside = require("./function-parentheses-space-inside")
const functionUrlDataUris = require("./function-url-data-uris")
const functionUrlNoSchemeRelative = require("./function-url-no-scheme-relative")
const functionUrlQuotes = require("./function-url-quotes")
const functionUrlSchemeWhitelist = require("./function-url-scheme-whitelist")
const functionWhitelist = require("./function-whitelist")
const functionWhitespaceAfter = require("./function-whitespace-after")
const indentation = require("./indentation")
const keyframeDeclarationNoImportant = require("./keyframe-declaration-no-important")
const lengthZeroNoUnit = require("./length-zero-no-unit")
const maxEmptyLines = require("./max-empty-lines")
const maxLineLength = require("./max-line-length")
const maxNestingDepth = require("./max-nesting-depth")
const mediaFeatureColonSpaceAfter = require("./media-feature-colon-space-after")
const mediaFeatureColonSpaceBefore = require("./media-feature-colon-space-before")
const mediaFeatureNameBlacklist = require("./media-feature-name-blacklist")
const mediaFeatureNameCase = require("./media-feature-name-case")
const mediaFeatureNameNoUnknown = require("./media-feature-name-no-unknown")
const mediaFeatureNameNoVendorPrefix = require("./media-feature-name-no-vendor-prefix")
const mediaFeatureNameWhitelist = require("./media-feature-name-whitelist")
const mediaFeatureNoMissingPunctuation = require("./media-feature-no-missing-punctuation")
const mediaFeatureParenthesesSpaceInside = require("./media-feature-parentheses-space-inside")
const mediaFeatureRangeOperatorSpaceAfter = require("./media-feature-range-operator-space-after")
const mediaFeatureRangeOperatorSpaceBefore = require("./media-feature-range-operator-space-before")
const mediaQueryListCommaNewlineAfter = require("./media-query-list-comma-newline-after")
const mediaQueryListCommaNewlineBefore = require("./media-query-list-comma-newline-before")
const mediaQueryListCommaSpaceAfter = require("./media-query-list-comma-space-after")
const mediaQueryListCommaSpaceBefore = require("./media-query-list-comma-space-before")
const noBrowserHacks = require("./no-browser-hacks")
const noDescendingSpecificity = require("./no-descending-specificity")
const noDuplicateSelectors = require("./no-duplicate-selectors")
const noEmptySource = require("./no-empty-source")
const noEolWhitespace = require("./no-eol-whitespace")
const noExtraSemicolons = require("./no-extra-semicolons")
const noIndistinguishableColors = require("./no-indistinguishable-colors")
const noInvalidDoubleSlashComments = require("./no-invalid-double-slash-comments")
const noMissingEndOfSourceNewline = require("./no-missing-end-of-source-newline")
const noSupportedBrowserFeatures = require("./no-unsupported-browser-features")
const noUnknownAnimations = require("./no-unknown-animations")
const numberLeadingZero = require("./number-leading-zero")
const numberMaxPrecision = require("./number-max-precision")
const numberNoTrailingZeros = require("./number-no-trailing-zeros")
const propertyBlacklist = require("./property-blacklist")
const propertyCase = require("./property-case")
const propertyNoUnknown = require("./property-no-unknown")
const propertyNoVendorPrefix = require("./property-no-vendor-prefix")
const propertyWhitelist = require("./property-whitelist")
const rootNoStandardProperties = require("./root-no-standard-properties")
const ruleEmptyLineBefore = require("./rule-empty-line-before")
const ruleNestedEmptyLineBefore = require("./rule-nested-empty-line-before")
const ruleNonNestedEmptyLineBefore = require("./rule-non-nested-empty-line-before")
const selectorAttributeBracketsSpaceInside = require("./selector-attribute-brackets-space-inside")
const selectorAttributeOperatorBlacklist = require("./selector-attribute-operator-blacklist")
const selectorAttributeOperatorSpaceAfter = require("./selector-attribute-operator-space-after")
const selectorAttributeOperatorSpaceBefore = require("./selector-attribute-operator-space-before")
const selectorAttributeOperatorWhitelist = require("./selector-attribute-operator-whitelist")
const selectorAttributeQuotes = require("./selector-attribute-quotes")
const selectorClassPattern = require("./selector-class-pattern")
const selectorCombinatorSpaceAfter = require("./selector-combinator-space-after")
const selectorCombinatorSpaceBefore = require("./selector-combinator-space-before")
const selectorDescendantCombinatorNoNonSpace = require("./selector-descendant-combinator-no-non-space")
const selectorIdPattern = require("./selector-id-pattern")
const selectorListCommaNewlineAfter = require("./selector-list-comma-newline-after")
const selectorListCommaNewlineBefore = require("./selector-list-comma-newline-before")
const selectorListCommaSpaceAfter = require("./selector-list-comma-space-after")
const selectorListCommaSpaceBefore = require("./selector-list-comma-space-before")
const selectorMaxCompoundSelectors = require("./selector-max-compound-selectors")
const selectorMaxEmptyLines = require("./selector-max-empty-lines")
const selectorMaxSpecificity = require("./selector-max-specificity")
const selectorNestedPattern = require("./selector-nested-pattern")
const selectorNoAttribute = require("./selector-no-attribute")
const selectorNoCombinator = require("./selector-no-combinator")
const selectorNoEmpty = require("./selector-no-empty")
const selectorNoId = require("./selector-no-id")
const selectorNoQualifyingType = require("./selector-no-qualifying-type")
const selectorNoType = require("./selector-no-type")
const selectorNoUniversal = require("./selector-no-universal")
const selectorNoVendorPrefix = require("./selector-no-vendor-prefix")
const selectorPseudoClassBlacklist = require("./selector-pseudo-class-blacklist")
const selectorPseudoClassCase = require("./selector-pseudo-class-case")
const selectorPseudoClassNoUnknown = require("./selector-pseudo-class-no-unknown")
const selectorPseudoClassParenthesesSpaceInside = require("./selector-pseudo-class-parentheses-space-inside")
const selectorPseudoClassWhitelist = require("./selector-pseudo-class-whitelist")
const selectorPseudoElementCase = require("./selector-pseudo-element-case")
const selectorPseudoElementColonNotation = require("./selector-pseudo-element-colon-notation")
const selectorPseudoElementNoUnknown = require("./selector-pseudo-element-no-unknown")
const selectorRootNoComposition = require("./selector-root-no-composition")
const selectorTypeCase = require("./selector-type-case")
const selectorTypeNoUnknown = require("./selector-type-no-unknown")
const shorthandPropertyNoRedundantValues = require("./shorthand-property-no-redundant-values")
const stringNoNewline = require("./string-no-newline")
const stringQuotes = require("./string-quotes")
const stylelintDisableReason = require("./stylelint-disable-reason")
const timeMinMilliseconds = require("./time-min-milliseconds")
const timeNoImperceptible = require("./time-no-imperceptible")
const unitBlacklist = require("./unit-blacklist")
const unitCase = require("./unit-case")
const unitNoUnknown = require("./unit-no-unknown")
const unitWhitelist = require("./unit-whitelist")
const valueKeywordCase = require("./value-keyword-case")
const valueListCommaNewlineAfter = require("./value-list-comma-newline-after")
const valueListCommaNewlineBefore = require("./value-list-comma-newline-before")
const valueListCommaSpaceAfter = require("./value-list-comma-space-after")
const valueListCommaSpaceBefore = require("./value-list-comma-space-before")
const valueListMaxEmptyLines = require("./value-list-max-empty-lines")
const valueNoVendorPrefix = require("./value-no-vendor-prefix")
module.exports = {
"at-rule-blacklist": atRuleBlacklist,
"at-rule-empty-line-before": atRuleEmptyLineBefore,
"at-rule-name-case": atRuleNameCase,
"at-rule-name-newline-after": atRuleNameNewlineAfter,
"at-rule-semicolon-space-before": atRuleSemicolonSpaceBefore,
"at-rule-name-space-after": atRuleNameSpaceAfter,
"at-rule-no-unknown": atRuleNoUnknown,
"at-rule-no-vendor-prefix": atRuleNoVendorPrefix,
"at-rule-semicolon-newline-after": atRuleSemicolonNewlineAfter,
"at-rule-whitelist": atRuleWhitelist,
"block-closing-brace-empty-line-before": blockClosingBraceEmptyLineBefore,
"block-closing-brace-newline-after": blockClosingBraceNewlineAfter,
"block-closing-brace-newline-before": blockClosingBraceNewlineBefore,
"block-closing-brace-space-after": blockClosingBraceSpaceAfter,
"block-closing-brace-space-before": blockClosingBraceSpaceBefore,
"block-no-empty": blockNoEmpty,
"block-no-single-line": blockNoSingleLine,
"block-opening-brace-newline-after": blockOpeningBraceNewlineAfter,
"block-opening-brace-newline-before": blockOpeningBraceNewlineBefore,
"block-opening-brace-space-after": blockOpeningBraceSpaceAfter,
"block-opening-brace-space-before": blockOpeningBraceSpaceBefore,
"color-hex-case": colorHexCase,
"color-hex-length": colorHexLength,
"color-named": colorNamed,
"color-no-hex": colorNoHex,
"color-no-invalid-hex": colorNoInvalidHex,
"comment-empty-line-before": commentEmptyLineBefore,
"comment-no-empty": commentNoEmpty,
"comment-whitespace-inside": commentWhitespaceInside,
"comment-word-blacklist": commentWordBlacklist,
"custom-media-pattern": customMediaPattern,
"custom-property-empty-line-before": customPropertyEmptyLineBefore,
"custom-property-no-outside-root": customPropertyNoOutsideRoot,
"custom-property-pattern": customPropertyPattern,
"declaration-bang-space-after": declarationBangSpaceAfter,
"declaration-bang-space-before": declarationBangSpaceBefore,
"declaration-block-no-duplicate-properties": declarationBlockNoDuplicateProperties,
"declaration-block-no-ignored-properties": declarationBlockNoIgnoredProperties,
"declaration-block-no-redundant-longhand-properties": declarationBlockNoRedundantLonghandProperties,
"declaration-block-no-shorthand-property-overrides": declarationBlockNoShorthandPropertyOverrides,
"declaration-block-properties-order": declarationBlockPropertiesOrder,
"declaration-block-semicolon-newline-after": declarationBlockSemicolonNewlineAfter,
"declaration-block-semicolon-newline-before": declarationBlockSemicolonNewlineBefore,
"declaration-block-semicolon-space-after": declarationBlockSemicolonSpaceAfter,
"declaration-block-semicolon-space-before": declarationBlockSemicolonSpaceBefore,
"declaration-block-single-line-max-declarations": declarationBlockSingleLineMaxDeclarations,
"declaration-block-trailing-semicolon": declarationBlockTrailingSemicolon,
"declaration-colon-newline-after": declarationColonNewlineAfter,
"declaration-colon-space-after": declarationColonSpaceAfter,
"declaration-colon-space-before": declarationColonSpaceBefore,
"declaration-empty-line-before": declarationEmptyLineBefore,
"declaration-no-important": declarationNoImportant,
"declaration-property-unit-blacklist": declarationPropertyUnitBlacklist,
"declaration-property-unit-whitelist": declarationPropertyUnitWhitelist,
"declaration-property-value-blacklist": declarationPropertyValueBlacklist,
"declaration-property-value-whitelist": declarationPropertyValueWhitelist,
"font-family-name-quotes": fontFamilyNameQuotes,
"font-family-no-duplicate-names": fontFamilyNoDuplicateNames,
"font-weight-notation": fontWeightNotation,
"function-blacklist": functionBlacklist,
"function-calc-no-unspaced-operator": functionCalcNoUnspacedOperator,
"function-comma-newline-after": functionCommaNewlineAfter,
"function-comma-newline-before": functionCommaNewlineBefore,
"function-comma-space-after": functionCommaSpaceAfter,
"function-comma-space-before": functionCommaSpaceBefore,
"function-linear-gradient-no-nonstandard-direction": functionLinearGradientNoNonstandardDirection,
"function-max-empty-lines": functionMaxEmptyLines,
"function-name-case": functionNameCase,
"function-parentheses-newline-inside": functionParenthesesNewlineInside,
"function-parentheses-space-inside": functionParenthesesSpaceInside,
"function-url-data-uris": functionUrlDataUris,
"function-url-no-scheme-relative": functionUrlNoSchemeRelative,
"function-url-quotes": functionUrlQuotes,
"function-url-scheme-whitelist": functionUrlSchemeWhitelist,
"function-whitelist": functionWhitelist,
"function-whitespace-after": functionWhitespaceAfter,
"indentation": indentation, // eslint-disable-line object-shorthand
"keyframe-declaration-no-important": keyframeDeclarationNoImportant,
"length-zero-no-unit": lengthZeroNoUnit,
"max-empty-lines": maxEmptyLines,
"max-line-length": maxLineLength,
"max-nesting-depth": maxNestingDepth,
"media-feature-colon-space-after": mediaFeatureColonSpaceAfter,
"media-feature-colon-space-before": mediaFeatureColonSpaceBefore,
"media-feature-name-blacklist": mediaFeatureNameBlacklist,
"media-feature-name-case": mediaFeatureNameCase,
"media-feature-name-no-unknown": mediaFeatureNameNoUnknown,
"media-feature-name-no-vendor-prefix": mediaFeatureNameNoVendorPrefix,
"media-feature-name-whitelist": mediaFeatureNameWhitelist,
"media-feature-no-missing-punctuation": mediaFeatureNoMissingPunctuation,
"media-feature-parentheses-space-inside": mediaFeatureParenthesesSpaceInside,
"media-feature-range-operator-space-after": mediaFeatureRangeOperatorSpaceAfter,
"media-feature-range-operator-space-before": mediaFeatureRangeOperatorSpaceBefore,
"media-query-list-comma-newline-after": mediaQueryListCommaNewlineAfter,
"media-query-list-comma-newline-before": mediaQueryListCommaNewlineBefore,
"media-query-list-comma-space-after": mediaQueryListCommaSpaceAfter,
"media-query-list-comma-space-before": mediaQueryListCommaSpaceBefore,
"no-browser-hacks": noBrowserHacks,
"no-descending-specificity": noDescendingSpecificity,
"no-duplicate-selectors": noDuplicateSelectors,
"no-empty-source": noEmptySource,
"no-eol-whitespace": noEolWhitespace,
"no-extra-semicolons": noExtraSemicolons,
"no-indistinguishable-colors": noIndistinguishableColors,
"no-invalid-double-slash-comments": noInvalidDoubleSlashComments,
"no-missing-end-of-source-newline": noMissingEndOfSourceNewline,
"no-unknown-animations": noUnknownAnimations,
"no-unsupported-browser-features": noSupportedBrowserFeatures,
"number-leading-zero": numberLeadingZero,
"number-max-precision": numberMaxPrecision,
"number-no-trailing-zeros": numberNoTrailingZeros,
"property-blacklist": propertyBlacklist,
"property-case": propertyCase,
"property-no-unknown": propertyNoUnknown,
"property-no-vendor-prefix": propertyNoVendorPrefix,
"property-whitelist": propertyWhitelist,
"root-no-standard-properties": rootNoStandardProperties,
"rule-empty-line-before": ruleEmptyLineBefore,
"rule-nested-empty-line-before": ruleNestedEmptyLineBefore,
"rule-non-nested-empty-line-before": ruleNonNestedEmptyLineBefore,
"selector-attribute-brackets-space-inside": selectorAttributeBracketsSpaceInside,
"selector-attribute-operator-blacklist": selectorAttributeOperatorBlacklist,
"selector-attribute-operator-space-after": selectorAttributeOperatorSpaceAfter,
"selector-attribute-operator-space-before": selectorAttributeOperatorSpaceBefore,
"selector-attribute-operator-whitelist": selectorAttributeOperatorWhitelist,
"selector-attribute-quotes": selectorAttributeQuotes,
"selector-class-pattern": selectorClassPattern,
"selector-combinator-space-after": selectorCombinatorSpaceAfter,
"selector-combinator-space-before": selectorCombinatorSpaceBefore,
"selector-descendant-combinator-no-non-space": selectorDescendantCombinatorNoNonSpace,
"selector-id-pattern": selectorIdPattern,
"selector-list-comma-newline-after": selectorListCommaNewlineAfter,
"selector-list-comma-newline-before": selectorListCommaNewlineBefore,
"selector-list-comma-space-after": selectorListCommaSpaceAfter,
"selector-list-comma-space-before": selectorListCommaSpaceBefore,
"selector-max-compound-selectors": selectorMaxCompoundSelectors,
"selector-max-empty-lines": selectorMaxEmptyLines,
"selector-max-specificity": selectorMaxSpecificity,
"selector-nested-pattern": selectorNestedPattern,
"selector-no-attribute": selectorNoAttribute,
"selector-no-empty": selectorNoEmpty,
"selector-no-combinator": selectorNoCombinator,
"selector-no-id": selectorNoId,
"selector-no-qualifying-type": selectorNoQualifyingType,
"selector-no-type": selectorNoType,
"selector-no-universal": selectorNoUniversal,
"selector-no-vendor-prefix": selectorNoVendorPrefix,
"selector-pseudo-class-blacklist": selectorPseudoClassBlacklist,
"selector-pseudo-class-case": selectorPseudoClassCase,
"selector-pseudo-class-no-unknown": selectorPseudoClassNoUnknown,
"selector-pseudo-class-parentheses-space-inside": selectorPseudoClassParenthesesSpaceInside,
"selector-pseudo-class-whitelist": selectorPseudoClassWhitelist,
"selector-pseudo-element-case": selectorPseudoElementCase,
"selector-pseudo-element-colon-notation": selectorPseudoElementColonNotation,
"selector-pseudo-element-no-unknown": selectorPseudoElementNoUnknown,
"selector-root-no-composition": selectorRootNoComposition,
"selector-type-case": selectorTypeCase,
"selector-type-no-unknown": selectorTypeNoUnknown,
"shorthand-property-no-redundant-values": shorthandPropertyNoRedundantValues,
"string-no-newline": stringNoNewline,
"string-quotes": stringQuotes,
"stylelint-disable-reason": stylelintDisableReason,
"time-min-milliseconds": timeMinMilliseconds,
"time-no-imperceptible": timeNoImperceptible,
"unit-blacklist": unitBlacklist,
"unit-case": unitCase,
"unit-no-unknown": unitNoUnknown,
"unit-whitelist": unitWhitelist,
"value-keyword-case": valueKeywordCase,
"value-list-comma-newline-after": valueListCommaNewlineAfter,
"value-list-comma-newline-before": valueListCommaNewlineBefore,
"value-list-comma-space-after": valueListCommaSpaceAfter,
"value-list-comma-space-before": valueListCommaSpaceBefore,
"value-list-max-empty-lines": valueListMaxEmptyLines,
"value-no-vendor-prefix": valueNoVendorPrefix,
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../utils/atRuleParamIndex")
const report = require("../utils/report")
const styleSearch = require("style-search")
module.exports = function (opts) {
opts.root.walkAtRules(/^media$/i, atRule => {
const params = atRule.params
styleSearch({ source: params, target: ":" }, match => {
checkColon(params, match.startIndex, atRule)
})
})
function checkColon(source, index, node) {
opts.locationChecker({ source, index, err: m => report({
message: m,
node,
index: index + atRuleParamIndex(node),
result: opts.result,
ruleName: opts.checkedRuleName,
}),
})
}
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../utils/atRuleParamIndex")
const report = require("../utils/report")
const styleSearch = require("style-search")
module.exports = function (opts) {
opts.root.walkAtRules(/^media$/i, atRule => {
const params = atRule.params
styleSearch({ source: params, target: "," }, match => {
checkComma(params, match.startIndex, atRule)
})
})
function checkComma(source, index, node) {
opts.locationChecker({ source, index, err: m => report({
message: m,
node,
index: index + atRuleParamIndex(node),
result: opts.result,
ruleName: opts.checkedRuleName,
}),
})
}
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../utils/isStandardSyntaxRule")
const parseSelector = require("../utils/parseSelector")
const report = require("../utils/report")
const styleSearch = require("style-search")
module.exports = function (options) {
options.root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
if (rule.selector.indexOf("[") === -1 || rule.selector.indexOf("=") === -1) {
return
}
parseSelector(rule.selector, options.result, rule, selectorTree => {
selectorTree.walkAttributes(attributeNode => {
const operator = attributeNode.operator
if (!operator) {
return
}
const attributeNodeString = attributeNode.toString()
styleSearch({ source: attributeNodeString, target: operator }, match => {
const index = options.checkBeforeOperator ? match.startIndex : match.endIndex - 1
checkOperator(attributeNodeString, index, rule, attributeNode.sourceIndex, operator)
})
})
})
function checkOperator(source, index, node, attributeIndex, operator) {
options.locationChecker({
source,
index,
err: m => report({
message: m.replace(options.checkBeforeOperator ? operator[0] : operator[operator.length - 1], operator),
node,
index: attributeIndex + index,
result: options.result,
ruleName: options.checkedRuleName,
}),
})
}
})
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 1 1 1 1 1 1 | "use strict"
const report = require("../utils/report")
const _ = require("lodash")
const punctuationSets = require("../reference/punctuationSets")
const styleSearch = require("style-search")
module.exports = function (opts) {
opts.root.walkRules(rule => {
// Check each selector individually, instead of all as one string,
// in case some that aren't the first begin with combinators (nesting syntax)
rule.selectors.forEach(selector => {
styleSearch({
source: selector,
target: _.toArray(punctuationSets.nonSpaceCombinators),
parentheticals: "skip",
}, match => {
const endIndex = match.endIndex,
startIndex = match.startIndex,
target = match.target
// Catch ~= in attribute selectors
if (target === "~" && selector[endIndex] === "=") {
return
}
// Catch escaped combinator-like character
if (selector[startIndex - 1] === "\\") {
return
}
check(selector, startIndex, rule)
})
})
})
function check(source, index, node) {
opts.locationChecker({ source, index, err: m => report({
message: m,
node,
index,
result: opts.result,
ruleName: opts.checkedRuleName,
}),
})
}
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../utils/isStandardSyntaxRule")
const report = require("../utils/report")
const styleSearch = require("style-search")
module.exports = function (opts) {
opts.root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
const selector = rule.selector
styleSearch({
source: selector,
target: ",",
functionArguments: "skip",
}, match => {
checkDelimiter(selector, match.startIndex, rule)
})
})
function checkDelimiter(source, index, node) {
opts.locationChecker({ source, index, err: m => report({
message: m,
node,
index,
result: opts.result,
ruleName: opts.checkedRuleName,
}),
})
}
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxDeclaration = require("../utils/isStandardSyntaxDeclaration")
const isStandardSyntaxProperty = require("../utils/isStandardSyntaxProperty")
const report = require("../utils/report")
const styleSearch = require("style-search")
module.exports = function (opts) {
opts.root.walkDecls(decl => {
if (!isStandardSyntaxDeclaration(decl) || !isStandardSyntaxProperty(decl.prop)) {
return
}
styleSearch({
source: decl.toString(),
target: ",",
functionArguments: "skip",
}, match => {
checkComma(decl.toString(), match.startIndex, decl)
})
})
function checkComma(source, index, node) {
opts.locationChecker({
source,
index,
err: m => {
report({
message: m,
node,
index,
result: opts.result,
ruleName: opts.checkedRuleName,
})
},
})
}
}
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 52.17% | (12 / 23) | 0% | (0 / 4) | 0% | (0 / 1) | 52.17% | (12 / 23) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const postcss = require("postcss")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "at-rule-blacklist"
const messages = ruleMessages(ruleName, {
rejected: name => `Unexpected at-rule "${name}"`,
})
const rule = function (blacklistInput) {
// To allow for just a string as a parameter (not only arrays of strings)
const blacklist = [].concat(blacklistInput)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: blacklist,
possible: [_.isString],
})
if (!validOptions) {
return
}
root.walkAtRules(atRule => {
const name = atRule.name
if (blacklist.indexOf(postcss.vendor.unprefixed(name).toLowerCase()) === -1) {
return
}
report({
message: messages.rejected(name),
node: atRule,
result,
ruleName,
})
})
}
}
rule.primaryOptionArray = true
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 33.33% | (18 / 54) | 0% | (0 / 72) | 0% | (0 / 6) | 33.33% | (18 / 54) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const hasBlock = require("../../utils/hasBlock")
const hasEmptyLine = require("../../utils/hasEmptyLine")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "at-rule-empty-line-before"
const messages = ruleMessages(ruleName, {
expected: "Expected empty line before at-rule",
rejected: "Unexpected empty line before at-rule",
})
const rule = function (expectation, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
}, {
actual: options,
possible: {
except: [
"after-same-name",
"all-nested",
"inside-block",
"blockless-after-same-name-blockless",
"blockless-group",
"blockless-after-blockless",
"first-nested",
],
ignore: [
"after-comment",
"all-nested",
"inside-block",
"blockless-after-same-name-blockless",
"blockless-group",
"blockless-after-blockless",
],
ignoreAtRules: [_.isString],
},
optional: true,
})
if (!validOptions) {
return
}
if (
optionsMatches(options, "ignore", "all-nested")
|| optionsMatches(options, "except", "all-nested")
) {
result.warn((
"'at-rule-empty-line-before\'s' \"all-nested\" option has been deprecated and in 8.0 will be removed. " +
"Instead use the \"inside-block\" option."
), {
stylelintType: "deprecation",
stylelintReference: "https://stylelint.io/user-guide/rules/at-rule-empty-line-before/",
})
}
if (
optionsMatches(options, "ignore", "blockless-group")
|| optionsMatches(options, "except", "blockless-group")
) {
result.warn((
"'at-rule-empty-line-before\'s' \"blockless-group\" option has been deprecated and in 8.0 will be removed. " +
"Instead use the \"blockless-after-blockless\" option."
), {
stylelintType: "deprecation",
stylelintReference: "https://stylelint.io/user-guide/rules/at-rule-empty-line-before/",
})
}
root.walkAtRules(atRule => {
// Ignore the first node
if (atRule === root.first) {
return
}
// Return early if at-rule is to be ignored
if (optionsMatches(options, "ignoreAtRules", atRule.name)) {
return
}
// Optionally ignore the expectation if the node is blockless
if (
optionsMatches(options, "ignore", "blockless-group")
&& !hasBlock(atRule)
|| optionsMatches(options, "ignore", "blockless-after-blockless")
&& !hasBlock(atRule)
) {
return
}
const isNested = atRule.parent !== root
const previousNode = atRule.prev()
// Optionally ignore the expection if the node is blockless
// and following another blockless at-rule with the same name
if (
optionsMatches(options, "ignore", "blockless-after-same-name-blockless")
&& isBlocklessAfterSameNameBlockless()
) {
return
}
// Optionally ignore the expectation if the node is inside a block
if (
optionsMatches(options, "ignore", "all-nested")
&& isNested
|| optionsMatches(options, "ignore", "inside-block")
&& isNested
) {
return
}
// Optionally ignore the expectation if a comment precedes this node
if (
optionsMatches(options, "ignore", "after-comment")
&& isAfterComment()
) {
return
}
const hasEmptyLineBefore = hasEmptyLine(atRule.raws.before)
let expectEmptyLineBefore = expectation === "always"
? true
: false
// Optionally reverse the expectation if any exceptions apply
if (
optionsMatches(options, "except", "after-same-name")
&& isAfterSameName()
|| optionsMatches(options, "except", "all-nested")
&& isNested
|| optionsMatches(options, "except", "inside-block")
&& isNested
|| optionsMatches(options, "except", "first-nested")
&& isFirstNested()
|| optionsMatches(options, "except", "blockless-group")
&& isBlocklessAfterBlockless()
|| optionsMatches(options, "except", "blockless-after-blockless")
&& isBlocklessAfterBlockless()
|| optionsMatches(options, "except", "blockless-after-same-name-blockless")
&& isBlocklessAfterSameNameBlockless()
) {
expectEmptyLineBefore = !expectEmptyLineBefore
}
// Return if the expectation is met
if (expectEmptyLineBefore === hasEmptyLineBefore) {
return
}
const message = expectEmptyLineBefore
? messages.expected
: messages.rejected
report({ message, node: atRule, result, ruleName })
function isAfterComment() {
return previousNode
&& previousNode.type === "comment"
}
function isBlocklessAfterBlockless() {
return previousNode
&& previousNode.type === "atrule"
&& !hasBlock(previousNode)
&& !hasBlock(atRule)
}
function isBlocklessAfterSameNameBlockless() {
return !hasBlock(atRule)
&& previousNode
&& !hasBlock(previousNode)
&& previousNode.type === "atrule"
&& previousNode.name == atRule.name
}
function isAfterSameName() {
return previousNode
&& previousNode.type === "atrule"
&& previousNode.name === atRule.name
}
function isFirstNested() {
return isNested
&& atRule === atRule.parent.first
}
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 45% | (9 / 20) | 0% | (0 / 6) | 0% | (0 / 1) | 45% | (9 / 20) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 1 1 1 1 1 1 1 1 1 | "use strict"
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "at-rule-name-case"
const messages = ruleMessages(ruleName, {
expected: (actual, expected) => `Expected "${actual}" to be "${expected}"`,
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"lower",
"upper",
],
})
if (!validOptions) {
return
}
root.walkAtRules(atRule => {
const name = atRule.name
const expectedName = expectation === "lower"
? name.toLowerCase()
: name.toUpperCase()
if (name === expectedName) {
return
}
report({
message: messages.expected(name, expectedName),
node: atRule,
ruleName,
result,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 58.82% | (10 / 17) | 0% | (0 / 2) | 0% | (0 / 1) | 58.82% | (10 / 17) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleNameSpaceChecker = require("../atRuleNameSpaceChecker")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "at-rule-name-newline-after"
const messages = ruleMessages(ruleName, {
expectedAfter: name => `Expected newline after at-rule name \"${name}\"`,
})
const rule = function (expectation) {
const checker = whitespaceChecker("newline", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"always-multi-line",
],
})
if (!validOptions) {
return
}
atRuleNameSpaceChecker({
root,
result,
locationChecker: checker.afterOneOnly,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 58.82% | (10 / 17) | 0% | (0 / 2) | 0% | (0 / 1) | 58.82% | (10 / 17) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleNameSpaceChecker = require("../atRuleNameSpaceChecker")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "at-rule-name-space-after"
const messages = ruleMessages(ruleName, {
expectedAfter: name => `Expected single space after at-rule name \"${name}\"`,
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"always-single-line",
],
})
if (!validOptions) {
return
}
atRuleNameSpaceChecker({
root,
result,
locationChecker: checker.after,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 52% | (13 / 25) | 0% | (0 / 8) | 0% | (0 / 1) | 52% | (13 / 25) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const keywordSets = require("../../reference/keywordSets")
const optionsMatches = require("../../utils/optionsMatches")
const postcss = require("postcss")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "at-rule-no-unknown"
const messages = ruleMessages(ruleName, {
rejected: atRule => `Unexpected unknown at-rule "${atRule}"`,
})
const rule = function (actual, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual }, {
actual: options,
possible: {
ignoreAtRules: [_.isString],
},
optional: true,
})
if (!validOptions) {
return
}
root.walkAtRules(atRule => {
const name = atRule.name
// Return early if at-rule is to be ignored
if (optionsMatches(options, "ignoreAtRules", atRule.name)) {
return
}
if (
postcss.vendor.prefix(name)
|| keywordSets.atRules.has(name.toLowerCase())
) {
return
}
report({
message: messages.rejected(`@${name}`),
node: atRule,
ruleName,
result,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 44% | (11 / 25) | 0% | (0 / 8) | 0% | (0 / 2) | 44% | (11 / 25) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isAutoprefixable = require("../../utils/isAutoprefixable")
const isStandardSyntaxAtRule = require("../../utils/isStandardSyntaxAtRule")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "at-rule-no-vendor-prefix"
const messages = ruleMessages(ruleName, {
rejected: p => `Unexpected vendor-prefixed at-rule "@${p}"`,
})
const rule = function (actual) {
return function (root, result) {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkAtRules(atRule => {
if (!isStandardSyntaxAtRule(atRule)) {
return
}
const name = atRule.name
if (name[0] !== "-") {
return
}
if (!isAutoprefixable.atRuleName(name)) {
return
}
report({
message: messages.rejected(name),
node: atRule,
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 43.33% | (13 / 30) | 0% | (0 / 8) | 0% | (0 / 1) | 43.33% | (13 / 30) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const hasBlock = require("../../utils/hasBlock")
const nextNonCommentNode = require("../../utils/nextNonCommentNode")
const rawNodeString = require("../../utils/rawNodeString")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "at-rule-semicolon-newline-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected newline after \";\"",
})
const rule = function (actual) {
const checker = whitespaceChecker("newline", actual, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual,
possible: ["always"],
})
if (!validOptions) {
return
}
root.walkAtRules(atRule => {
const nextNode = atRule.next()
if (!nextNode) {
return
}
if (hasBlock(atRule)) {
return
}
// Allow an end-of-line comment
const nodeToCheck = nextNonCommentNode(nextNode)
if (!nodeToCheck) {
return
}
checker.afterOneOnly({
source: rawNodeString(nodeToCheck),
index: -1,
err: msg => {
report({
message: msg,
node: atRule,
index: atRule.toString().length + 1,
result,
ruleName,
})
},
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 48% | (12 / 25) | 0% | (0 / 4) | 0% | (0 / 1) | 48% | (12 / 25) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const hasBlock = require("../../utils/hasBlock")
const rawNodeString = require("../../utils/rawNodeString")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "at-rule-semicolon-space-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected single space before \";\"",
rejectedBefore: () => "Unexpected whitespace before \";\"",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
root.walkAtRules(atRule => {
if (hasBlock(atRule)) {
return
}
const nodeString = rawNodeString(atRule)
checker.before({
source: nodeString,
index: nodeString.length,
err: m => {
report({
message: m,
node: atRule,
index: nodeString.length - 1,
result,
ruleName,
})
},
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 52.17% | (12 / 23) | 0% | (0 / 4) | 0% | (0 / 1) | 52.17% | (12 / 23) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const postcss = require("postcss")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "at-rule-whitelist"
const messages = ruleMessages(ruleName, {
rejected: name => `Unexpected at-rule "${name}"`,
})
const rule = function (whitelistInput) {
// To allow for just a string as a parameter (not only arrays of strings)
const whitelist = [].concat(whitelistInput)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: whitelist,
possible: [_.isString],
})
if (!validOptions) {
return
}
root.walkAtRules(atRule => {
const name = atRule.name
if (whitelist.indexOf(postcss.vendor.unprefixed(name).toLowerCase()) !== -1) {
return
}
report({
message: messages.rejected(name),
node: atRule,
result,
ruleName,
})
})
}
}
rule.primaryOptionArray = true
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 41.67% | (15 / 36) | 0% | (0 / 20) | 0% | (0 / 2) | 41.67% | (15 / 36) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const blockString = require("../../utils/blockString")
const hasBlock = require("../../utils/hasBlock")
const hasEmptyBlock = require("../../utils/hasEmptyBlock")
const hasEmptyLine = require("../../utils/hasEmptyLine")
const isSingleLineString = require("../../utils/isSingleLineString")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "block-closing-brace-empty-line-before"
const messages = ruleMessages(ruleName, {
expected: "Expected empty line before closing brace",
rejected: "Unexpected empty line before closing brace",
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always-multi-line",
"never",
],
})
if (!validOptions) {
return
}
// Check both kinds of statements: rules and at-rules
root.walkRules(check)
root.walkAtRules(check)
function check(statement) {
// Return early if blockless or has empty block
if (
!hasBlock(statement)
|| hasEmptyBlock(statement)
) {
return
}
// Get whitespace after ""}", ignoring extra semicolon
const before = (statement.raws.after || "").replace(/;+/, "")
if (before === undefined) {
return
}
// Calculate index
const statementString = statement.toString()
let index = statementString.length - 1
if (statementString[index - 1] === "\r") {
index -= 1
}
// Set expectation
const expectEmptyLineBefore = expectation === "always-multi-line"
&& !isSingleLineString(blockString(statement))
? true
: false
// Check for at least one empty line
const hasEmptyLineBefore = hasEmptyLine(before)
// Return if the expectation is met
if (expectEmptyLineBefore === hasEmptyLineBefore) {
return
}
const message = expectEmptyLineBefore
? messages.expected
: messages.rejected
report({
message,
result,
ruleName,
node: statement,
index,
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 34.78% | (16 / 46) | 0% | (0 / 21) | 0% | (0 / 2) | 34.78% | (16 / 46) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const blockString = require("../../utils/blockString")
const hasBlock = require("../../utils/hasBlock")
const optionsMatches = require("../../utils/optionsMatches")
const rawNodeString = require("../../utils/rawNodeString")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "block-closing-brace-newline-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected newline after \"}\"",
expectedAfterSingleLine: () => "Expected newline after \"}\" of a single-line block",
rejectedAfterSingleLine: () => "Unexpected whitespace after \"}\" of a single-line block",
expectedAfterMultiLine: () => "Expected newline after \"}\" of a multi-line block",
rejectedAfterMultiLine: () => "Unexpected whitespace after \"}\" of a multi-line block",
})
const rule = function (expectation, options) {
const checker = whitespaceChecker("newline", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"always-single-line",
"never-single-line",
"always-multi-line",
"never-multi-line",
],
}, {
actual: options,
possible: {
ignoreAtRules: [_.isString],
},
optional: true,
})
if (!validOptions) {
return
}
// Check both kinds of statements: rules and at-rules
root.walkRules(check)
root.walkAtRules(check)
function check(statement) {
if (!hasBlock(statement)) {
return
}
if (optionsMatches(options, "ignoreAtRules", statement.name)) {
return
}
const nextNode = statement.next()
if (!nextNode) {
return
}
// Allow an end-of-line comment x spaces after the brace
const nextNodeIsSingleLineComment = nextNode.type === "comment"
&& !/[^ ]/.test((nextNode.raws.before || ""))
&& nextNode.toString().indexOf("\n") === -1
const nodeToCheck = nextNodeIsSingleLineComment
? nextNode.next()
: nextNode
if (!nodeToCheck) {
return
}
let reportIndex = statement.toString().length
let source = rawNodeString(nodeToCheck)
// Skip a semicolon at the beginning, if any
if (
source
&& source[0] === ";"
) {
source = source.slice(1)
reportIndex++
}
// Only check one after, because there might be other
// spaces handled by the indentation rule
checker.afterOneOnly({
source,
index: -1,
lineCheckStr: blockString(statement),
err: msg => {
report({
message: msg,
node: statement,
index: reportIndex,
result,
ruleName,
})
},
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 40% | (16 / 40) | 0% | (0 / 27) | 0% | (0 / 3) | 40% | (16 / 40) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const blockString = require("../../utils/blockString")
const hasBlock = require("../../utils/hasBlock")
const hasEmptyBlock = require("../../utils/hasEmptyBlock")
const isSingleLineString = require("../../utils/isSingleLineString")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "block-closing-brace-newline-before"
const messages = ruleMessages(ruleName, {
expectedBefore: "Expected newline before \"}\"",
expectedBeforeMultiLine: "Expected newline before \"}\" of a multi-line block",
rejectedBeforeMultiLine: "Unexpected whitespace before \"}\" of a multi-line block",
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"always-multi-line",
"never-multi-line",
],
})
if (!validOptions) {
return
}
// Check both kinds of statements: rules and at-rules
root.walkRules(check)
root.walkAtRules(check)
function check(statement) {
// Return early if blockless or has empty block
if (
!hasBlock(statement)
|| hasEmptyBlock(statement)
) {
return
}
// Ignore extra semicolon
const after = (statement.raws.after || "").replace(/;+/, "")
if (after === undefined) {
return
}
const blockIsMultiLine = !isSingleLineString(blockString(statement))
const statementString = statement.toString()
let index = statementString.length - 2
if (statementString[index - 1] === "\r") {
index -= 1
}
// We're really just checking whether a
// newline *starts* the block's final space -- between
// the last declaration and the closing brace. We can
// ignore any other whitespace between them, because that
// will be checked by the indentation rule.
if (
!_.startsWith(after, "\n")
&& !_.startsWith(after, "\r\n")
) {
if (expectation === "always") {
complain(messages.expectedBefore)
} else if (
blockIsMultiLine
&& expectation === "always-multi-line"
) {
complain(messages.expectedBeforeMultiLine)
}
}
if (
after !== ""
&& blockIsMultiLine
&& expectation === "never-multi-line"
) {
complain(messages.rejectedBeforeMultiLine)
}
function complain(message) {
report({
message,
result,
ruleName,
node: statement,
index,
})
}
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 35.9% | (14 / 39) | 0% | (0 / 10) | 0% | (0 / 3) | 35.9% | (14 / 39) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const blockString = require("../../utils/blockString")
const hasBlock = require("../../utils/hasBlock")
const rawNodeString = require("../../utils/rawNodeString")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "block-closing-brace-space-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected single space after \"}\"",
rejectedAfter: () => "Unexpected whitespace after \"}\"",
expectedAfterSingleLine: () => "Expected single space after \"}\" of a single-line block",
rejectedAfterSingleLine: () => "Unexpected whitespace after \"}\" of a single-line block",
expectedAfterMultiLine: () => "Expected single space after \"}\" of a multi-line block",
rejectedAfterMultiLine: () => "Unexpected whitespace after \"}\" of a multi-line block",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return function (root, result) {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-single-line",
"never-single-line",
"always-multi-line",
"never-multi-line",
],
})
if (!validOptions) {
return
}
// Check both kinds of statements: rules and at-rules
root.walkRules(check)
root.walkAtRules(check)
function check(statement) {
const nextNode = statement.next()
if (!nextNode) {
return
}
if (!hasBlock(statement)) {
return
}
let reportIndex = statement.toString().length
let source = rawNodeString(nextNode)
// Skip a semicolon at the beginning, if any
if (
source
&& source[0] === ";"
) {
source = source.slice(1)
reportIndex++
}
checker.after({
source,
index: -1,
lineCheckStr: blockString(statement),
err: msg => {
report({
message: msg,
node: statement,
index: reportIndex,
result,
ruleName,
})
},
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 38.89% | (14 / 36) | 0% | (0 / 8) | 0% | (0 / 2) | 38.89% | (14 / 36) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const blockString = require("../../utils/blockString")
const hasBlock = require("../../utils/hasBlock")
const hasEmptyBlock = require("../../utils/hasEmptyBlock")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "block-closing-brace-space-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected single space before \"}\"",
rejectedBefore: () => "Unexpected whitespace before \"}\"",
expectedBeforeSingleLine: () => "Expected single space before \"}\" of a single-line block",
rejectedBeforeSingleLine: () => "Unexpected whitespace before \"}\" of a single-line block",
expectedBeforeMultiLine: () => "Expected single space before \"}\" of a multi-line block",
rejectedBeforeMultiLine: () => "Unexpected whitespace before \"}\" of a multi-line block",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual : expectation,
possible : [
"always",
"never",
"always-single-line",
"never-single-line",
"always-multi-line",
"never-multi-line",
],
})
if (!validOptions) {
return
}
// Check both kinds of statement: rules and at-rules
root.walkRules(check)
root.walkAtRules(check)
function check(statement) {
// Return early if blockless or has empty block
if (
!hasBlock(statement)
|| hasEmptyBlock(statement)
) {
return
}
const source = blockString(statement)
const statementString = statement.toString()
let index = statementString.length - 2
if (statementString[index - 1] === "\r") {
index -= 1
}
checker.before({
source,
index: source.length - 1,
err: msg => {
report({
message: msg,
node: statement,
index,
result,
ruleName,
})
},
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 50% | (12 / 24) | 0% | (0 / 6) | 0% | (0 / 2) | 50% | (12 / 24) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const beforeBlockString = require("../../utils/beforeBlockString")
const hasEmptyBlock = require("../../utils/hasEmptyBlock")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "block-no-empty"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected empty block",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
// Check both kinds of statements: rules and at-rules
root.walkRules(check)
root.walkAtRules(check)
function check(statement) {
if (!hasEmptyBlock(statement)) {
return
}
let index = beforeBlockString(statement, { noRawBefore: true }).length
// For empty blocks when using SugarSS parser
if (statement.raws.between === undefined) {
index--
}
report({
message: messages.rejected,
node: statement,
index,
result,
ruleName,
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 55.56% | (15 / 27) | 0% | (0 / 8) | 0% | (0 / 2) | 55.56% | (15 / 27) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const beforeBlockString = require("../../utils/beforeBlockString")
const blockString = require("../../utils/blockString")
const hasBlock = require("../../utils/hasBlock")
const hasEmptyBlock = require("../../utils/hasEmptyBlock")
const isSingleLineString = require("../../utils/isSingleLineString")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "block-no-single-line"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected single-line block",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
result.warn((
"'block-no-single-line' has been deprecated and in 8.0 will be removed. " +
"Instead use 'block-opening-brace-newline-after' and 'block-closing-brace-newline-before' with the \"always\" option."
), {
stylelintType: "deprecation",
stylelintReference: "https://stylelint.io/user-guide/rules/block-no-single-line/",
})
// Check both kinds of statements: rules and at-rules
root.walkRules(check)
root.walkAtRules(check)
function check(statement) {
if (
!hasBlock(statement)
|| hasEmptyBlock(statement)
) {
return
}
if (!isSingleLineString(blockString(statement))) {
return
}
report({
message: messages.rejected,
node: statement,
index: beforeBlockString(statement, { noRawBefore: true }).length,
result,
ruleName,
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 50% | (17 / 34) | 0% | (0 / 8) | 0% | (0 / 2) | 50% | (17 / 34) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const beforeBlockString = require("../../utils/beforeBlockString")
const blockString = require("../../utils/blockString")
const hasBlock = require("../../utils/hasBlock")
const hasEmptyBlock = require("../../utils/hasEmptyBlock")
const nextNonCommentNode = require("../../utils/nextNonCommentNode")
const rawNodeString = require("../../utils/rawNodeString")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "block-opening-brace-newline-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected newline after \"{\"",
expectedAfterMultiLine: () => "Expected newline after \"{\" of a multi-line block",
rejectedAfterMultiLine: () => "Unexpected whitespace after \"{\" of a multi-line block",
})
const rule = function (expectation) {
const checker = whitespaceChecker("newline", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"always-multi-line",
"never-multi-line",
],
})
if (!validOptions) {
return
}
// Check both kinds of statement: rules and at-rules
root.walkRules(check)
root.walkAtRules(check)
function check(statement) {
// Return early if blockless or has an empty block
if (
!hasBlock(statement)
|| hasEmptyBlock(statement)
) {
return
}
// Allow an end-of-line comment
const nodeToCheck = nextNonCommentNode(statement.first)
if (!nodeToCheck) {
return
}
checker.afterOneOnly({
source: rawNodeString(nodeToCheck),
index: -1,
lineCheckStr: blockString(statement),
err: m => {
report({
message: m,
node: statement,
index: beforeBlockString(statement, { noRawBefore: true }).length + 1,
result,
ruleName,
})
},
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 41.67% | (15 / 36) | 0% | (0 / 8) | 0% | (0 / 2) | 41.67% | (15 / 36) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const beforeBlockString = require("../../utils/beforeBlockString")
const blockString = require("../../utils/blockString")
const hasBlock = require("../../utils/hasBlock")
const hasEmptyBlock = require("../../utils/hasEmptyBlock")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "block-opening-brace-newline-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected newline before \"{\"",
expectedBeforeSingleLine: () => "Expected newline before \"{\" of a single-line block",
rejectedBeforeSingleLine: () => "Unexpected whitespace before \"{\" of a single-line block",
expectedBeforeMultiLine: () => "Expected newline before \"{\" of a multi-line block",
rejectedBeforeMultiLine: () => "Unexpected whitespace before \"{\" of a multi-line block",
})
const rule = function (expectation) {
const checker = whitespaceChecker("newline", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual : expectation,
possible : [
"always",
"always-single-line",
"never-single-line",
"always-multi-line",
"never-multi-line",
],
})
if (!validOptions) {
return
}
// Check both kinds of statement: rules and at-rules
root.walkRules(check)
root.walkAtRules(check)
function check(statement) {
// Return early if blockless or has an empty block
if (
!hasBlock(statement)
|| hasEmptyBlock(statement)
) {
return
}
const source = beforeBlockString(statement)
const beforeBraceNoRaw = beforeBlockString(statement, { noRawBefore: true })
let index = beforeBraceNoRaw.length - 1
if (beforeBraceNoRaw[index - 1] === "\r") {
index -= 1
}
checker.beforeAllowingIndentation({
lineCheckStr: blockString(statement),
source,
index: source.length,
err: m => {
report({
message: m,
node: statement,
index,
result,
ruleName,
})
},
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 46.88% | (15 / 32) | 0% | (0 / 6) | 0% | (0 / 2) | 46.88% | (15 / 32) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const beforeBlockString = require("../../utils/beforeBlockString")
const blockString = require("../../utils/blockString")
const hasBlock = require("../../utils/hasBlock")
const hasEmptyBlock = require("../../utils/hasEmptyBlock")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "block-opening-brace-space-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected single space after \"{\"",
rejectedAfter: () => "Unexpected whitespace after \"{\"",
expectedAfterSingleLine: () => "Expected single space after \"{\" of a single-line block",
rejectedAfterSingleLine: () => "Unexpected whitespace after \"{\" of a single-line block",
expectedAfterMultiLine: () => "Expected single space after \"{\" of a multi-line block",
rejectedAfterMultiLine: () => "Unexpected whitespace after \"{\" of a multi-line block",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-single-line",
"never-single-line",
"always-multi-line",
"never-multi-line",
],
})
if (!validOptions) {
return
}
// Check both kinds of statements: rules and at-rules
root.walkRules(check)
root.walkAtRules(check)
function check(statement) {
// Return early if blockless or has an empty block
if (
!hasBlock(statement)
|| hasEmptyBlock(statement)
) {
return
}
checker.after({
source: blockString(statement),
index: 0,
err: m => {
report({
message: m,
node: statement,
index: beforeBlockString(statement, { noRawBefore: true }).length + 1,
result,
ruleName,
})
},
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 41.46% | (17 / 41) | 0% | (0 / 10) | 0% | (0 / 2) | 41.46% | (17 / 41) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const beforeBlockString = require("../../utils/beforeBlockString")
const blockString = require("../../utils/blockString")
const hasBlock = require("../../utils/hasBlock")
const hasEmptyBlock = require("../../utils/hasEmptyBlock")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "block-opening-brace-space-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected single space before \"{\"",
rejectedBefore: () => "Unexpected whitespace before \"{\"",
expectedBeforeSingleLine: () => "Expected single space before \"{\" of a single-line block",
rejectedBeforeSingleLine: () => "Unexpected whitespace before \"{\" of a single-line block",
expectedBeforeMultiLine: () => "Expected single space before \"{\" of a multi-line block",
rejectedBeforeMultiLine: () => "Unexpected whitespace before \"{\" of a multi-line block",
})
const rule = function (expectation, options) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-single-line",
"never-single-line",
"always-multi-line",
"never-multi-line",
],
}, {
actual: options,
possible: {
ignoreAtRules: [_.isString],
},
optional: true,
})
if (!validOptions) {
return
}
// Check both kinds of statements: rules and at-rules
root.walkRules(check)
root.walkAtRules(check)
function check(statement) {
// Return early if blockless or has an empty block
if (
!hasBlock(statement)
|| hasEmptyBlock(statement)
) {
return
}
// Return early if at-rule is to be ignored
if (optionsMatches(options, "ignoreAtRules", statement.name)) {
return
}
const source = beforeBlockString(statement)
const beforeBraceNoRaw = beforeBlockString(statement, { noRawBefore: true })
let index = beforeBraceNoRaw.length - 1
if (beforeBraceNoRaw[index - 1] === "\r") {
index -= 1
}
checker.before({
source,
index: source.length,
lineCheckStr: blockString(statement),
err: m => {
report({
message: m,
node: statement,
index,
result,
ruleName,
})
},
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 37.93% | (11 / 29) | 0% | (0 / 8) | 0% | (0 / 1) | 37.93% | (11 / 29) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const blurFunctionArguments = require("../../utils/blurFunctionArguments")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const styleSearch = require("style-search")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "color-hex-case"
const messages = ruleMessages(ruleName, {
expected: (actual, expected) => `Expected "${actual}" to be "${expected}"`,
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"lower",
"upper",
],
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const declString = blurFunctionArguments(decl.toString(), "url")
styleSearch({ source: declString, target: "#" }, match => {
const hexMatch = /^#[0-9A-Za-z]+/.exec(declString.substr(match.startIndex))
if (!hexMatch) {
return
}
const hexValue = hexMatch[0]
const hexValueLower = hexValue.toLowerCase()
const hexValueUpper = hexValue.toUpperCase()
const expectedHex = expectation === "lower"
? hexValueLower
: hexValueUpper
if (hexValue === expectedHex) {
return
}
report({
message: messages.expected(hexValue, expectedHex),
node: decl,
index: match.startIndex,
result,
ruleName,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 31.71% | (13 / 41) | 0% | (0 / 22) | 0% | (0 / 4) | 31.71% | (13 / 41) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const styleSearch = require("style-search")
const ruleName = "color-hex-length"
const messages = ruleMessages(ruleName, {
expected: (actual, expected) => `Expected "${actual}" to be "${expected}"`,
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"short",
"long",
],
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const declString = decl.toString()
styleSearch({ source: declString, target: "#" }, match => {
const hexMatch = /^#[0-9A-Za-z]+/.exec(declString.substr(match.startIndex))
if (!hexMatch) {
return
}
const hexValue = hexMatch[0]
if (
expectation === "long"
&& hexValue.length !== 4
&& hexValue.length !== 5
) {
return
}
if (
expectation === "short"
&& (
hexValue.length < 6
|| !canShrink(hexValue)
)
) {
return
}
const variant = expectation === "long"
? longer
: shorter
report({
message: messages.expected(hexValue, variant(hexValue)),
node: decl,
index: match.startIndex,
result,
ruleName,
})
})
})
}
}
function canShrink(hex) {
hex = hex.toLowerCase()
return hex[1] === hex[2]
&& hex[3] === hex[4]
&& hex[5] === hex[6]
&& (hex.length === 7
|| hex.length === 9
&& hex[7] === hex[8]
)
}
function shorter(hex) {
let hexVariant = "#"
for (let i = 1; i < hex.length; i = i + 2) {
hexVariant += hex[i]
}
return hexVariant
}
function longer(hex) {
let hexVariant = "#"
for (let i = 1; i < hex.length; i++) {
hexVariant += hex[i] + hex[i]
}
return hexVariant
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 31.75% | (20 / 63) | 0% | (0 / 31) | 0% | (0 / 2) | 31.75% | (20 / 63) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const declarationValueIndex = require("../../utils/declarationValueIndex")
const isStandardSyntaxFunction = require("../../utils/isStandardSyntaxFunction")
const isStandardSyntaxValue = require("../../utils/isStandardSyntaxValue")
const keywordSets = require("../../reference/keywordSets")
const namedColorData = require("../../reference/namedColorData")
const optionsMatches = require("../../utils/optionsMatches")
const propertySets = require("../../reference/propertySets")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const valueParser = require("postcss-value-parser")
const ruleName = "color-named"
const messages = ruleMessages(ruleName, {
expected: (named, original) => `Expected "${original}" to be "${named}"`,
rejected: named => `Unexpected named color "${named}"`,
})
// Todo tested on case insensivity
const NODE_TYPES = [
"word",
"function",
]
const rule = function (expectation, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"never",
"always-where-possible",
],
}, {
actual: options,
possible: {
ignoreProperties: [_.isString],
ignore: ["inside-function"],
},
optional: true,
})
if (!validOptions) {
return
}
const namedColors = Object.keys(namedColorData)
root.walkDecls(decl => {
if (propertySets.acceptCustomIdents.has(decl.prop)) {
return
}
// Return early if the property is to be ignored
if (optionsMatches(options, "ignoreProperties", decl.prop)) {
return
}
valueParser(decl.value).walk(node => {
const value = node.value,
type = node.type,
sourceIndex = node.sourceIndex
if (
optionsMatches(options, "ignore", "inside-function")
&& type === "function"
) {
return false
}
if (!isStandardSyntaxFunction(node)) {
return false
}
if (!isStandardSyntaxValue(value)) {
return
}
// Return early if neither a word nor a function
if (NODE_TYPES.indexOf(type) === -1) {
return
}
// Check for named colors for "never" option
if (
expectation === "never"
&& type === "word"
&& namedColors.indexOf(value.toLowerCase()) !== -1
) {
complain(messages.rejected(value), decl, declarationValueIndex(decl) + sourceIndex)
return
}
// Check "always-where-possible" option ...
if (expectation !== "always-where-possible") {
return
}
// First by checking for alternative color function representations ...
if (
type === "function"
&& keywordSets.colorFunctionNames.has(value.toLowerCase())
) {
// Remove all spaces to match what's in `representations`
const normalizedFunctionString = valueParser.stringify(node).replace(/\s+/g, "")
let namedColor
for (let i = 0, l = namedColors.length; i < l; i++) {
namedColor = namedColors[i]
if (namedColorData[namedColor].func.indexOf(normalizedFunctionString.toLowerCase()) !== -1) {
complain(messages.expected(namedColor, normalizedFunctionString), decl, declarationValueIndex(decl) + sourceIndex)
return // Exit as soon as a problem is found
}
}
return
}
// Then by checking for alternative hex representations
let namedColor
for (let i = 0, l = namedColors.length; i < l; i++) {
namedColor = namedColors[i]
if (namedColorData[namedColor].hex.indexOf(value.toLowerCase()) !== -1) {
complain(messages.expected(namedColor, value), decl, declarationValueIndex(decl) + sourceIndex)
return // Exit as soon as a problem is found
}
}
})
})
function complain(message, node, index) {
report({
result,
ruleName,
message,
node,
index,
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 40% | (10 / 25) | 0% | (0 / 6) | 0% | (0 / 1) | 40% | (10 / 25) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const styleSearch = require("style-search")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "color-no-hex"
const messages = ruleMessages(ruleName, {
rejected: hex => `Unexpected hex color "${hex}"`,
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkDecls(decl => {
const declString = decl.toString()
styleSearch({ source: declString, target: "#" }, match => {
// If there's not a colon, comma, or whitespace character before, we'll assume this is
// not intended to be a hex color, but is instead something like the
// hash in a url() argument
if (!/[:,\s]/.test(declString[match.startIndex - 1])) {
return
}
const hexMatch = /^#[0-9A-Za-z]+/.exec(declString.substr(match.startIndex))
if (!hexMatch) {
return
}
const hexValue = hexMatch[0]
report({
message: messages.rejected(hexValue),
node: decl,
index: match.startIndex,
result,
ruleName,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 39.29% | (11 / 28) | 0% | (0 / 8) | 0% | (0 / 1) | 39.29% | (11 / 28) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isValidHex = require("../../utils/isValidHex")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const styleSearch = require("style-search")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "color-no-invalid-hex"
const messages = ruleMessages(ruleName, {
rejected: hex => `Unexpected invalid hex color "${hex}"`,
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkDecls(decl => {
const declString = decl.toString()
styleSearch({ source: declString, target: "#" }, match => {
// If there's not a colon, comma, or whitespace character before, we'll assume this is
// not intended to be a hex color, but is instead something like the
// hash in a url() argument
if (!/[:,\s]/.test(declString[match.startIndex - 1])) {
return
}
const hexMatch = /^#[0-9A-Za-z]+/.exec(declString.substr(match.startIndex))
if (!hexMatch) {
return
}
const hexValue = hexMatch[0]
if (isValidHex(hexValue)) {
return
}
report({
message: messages.rejected(hexValue),
node: decl,
index: match.startIndex,
result,
ruleName,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 28.57% | (12 / 42) | 0% | (0 / 37) | 0% | (0 / 1) | 28.57% | (12 / 42) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const hasEmptyLine = require("../../utils/hasEmptyLine")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "comment-empty-line-before"
const messages = ruleMessages(ruleName, {
expected: "Expected empty line before comment",
rejected: "Unexpected empty line before comment",
})
const stylelintCommandPrefix = "stylelint-"
const rule = function (expectation, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
}, {
actual: options,
possible: {
except: ["first-nested"],
ignore: [
"stylelint-commands",
"stylelint-command",
"between-comments",
"after-comment",
],
},
optional: true,
})
if (!validOptions) {
return
}
if (
optionsMatches(options, "ignore", "between-comments")
) {
result.warn((
"'comment-empty-line-before\'s' \"between-comments\" option has been deprecated and in 8.0 will be removed. " +
"Instead use the \"after-comment\" option."
), {
stylelintType: "deprecation",
stylelintReference: "https://stylelint.io/user-guide/rules/comment-empty-line-before/",
})
}
root.walkComments(comment => {
// Ignore the first node
if (comment === root.first) {
return
}
// Optionally ignore stylelint commands
if (
comment.text.indexOf(stylelintCommandPrefix) === 0
&& optionsMatches(options, "ignore", "stylelint-commands")
) {
return
}
// Optionally ignore newlines between comments
const prev = comment.prev()
if (
prev
&& prev.type === "comment"
&& optionsMatches(options, "ignore", "between-comments")
) {
return
}
if (
prev
&& prev.type === "comment"
&& optionsMatches(options, "ignore", "after-comment")
) {
return
}
if (
comment.raws.inline
|| comment.inline
) {
return
}
const before = (comment.raws.before || "")
// Ignore shared-line comments
if (before.indexOf("\n") === -1) {
return
}
const expectEmptyLineBefore = (() => {
if (
optionsMatches(options, "except", "first-nested")
&& comment.parent !== root
&& comment === comment.parent.first
) {
return false
}
return expectation === "always"
})()
const hasEmptyLineBefore = hasEmptyLine(before)
// Return if the expectation is met
if (expectEmptyLineBefore === hasEmptyLineBefore) {
return
}
const message = expectEmptyLineBefore
? messages.expected
: messages.rejected
report({
message,
node: comment,
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 47.37% | (9 / 19) | 0% | (0 / 10) | 0% | (0 / 1) | 47.37% | (9 / 19) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 1 1 1 1 1 1 1 1 1 | "use strict"
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "comment-no-empty"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected empty comment",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkComments(comment => {
// To ignore inline SCSS comments
if (
comment.raws.inline
|| comment.inline
) {
return
}
// To ignore comments that are not empty
if (
comment.text
&& comment.text.length !== 0
) {
return
}
report({
message: messages.rejected,
node: comment,
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 29.73% | (11 / 37) | 0% | (0 / 28) | 0% | (0 / 4) | 29.73% | (11 / 37) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isWhitespace = require("../../utils/isWhitespace")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "comment-whitespace-inside"
const messages = ruleMessages(ruleName, {
expectedOpening: "Expected whitespace after \"/*\"",
rejectedOpening: "Unexpected whitespace after \"/*\"",
expectedClosing: "Expected whitespace before \"*/\"",
rejectedClosing: "Unexpected whitespace before \"*/\"",
})
const rule = function (expectation) {
return function (root, result) {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
root.walkComments(function (comment) {
if (
comment.raws.inline
|| comment.inline
) {
return
}
const rawComment = comment.toString()
const firstFourChars = rawComment.substr(0, 4)
// Return early if sourcemap or copyright comment
if (/^\/\*[#!]\s/.test(firstFourChars)) {
return
}
const leftMatches = rawComment.match(/(^\/\*+)(\s)?/)
const rightMatches = rawComment.match(/(\s)?(\*+\/)$/)
const opener = leftMatches[1]
const leftSpace = leftMatches[2] || ""
const rightSpace = rightMatches[1] || ""
const closer = rightMatches[2]
if (
expectation === "never"
&& leftSpace !== ""
) {
complain(messages.rejectedOpening, opener.length)
}
if (
expectation === "always"
&& !isWhitespace(leftSpace)
) {
complain(messages.expectedOpening, opener.length)
}
if (
expectation === "never"
&& rightSpace !== ""
) {
complain(messages.rejectedClosing, comment.toString().length - closer.length - 1)
}
if (
expectation === "always"
&& !isWhitespace(rightSpace)
) {
complain(messages.expectedClosing, comment.toString().length - closer.length - 1)
}
function complain(message, index) {
report({
message,
index,
result,
ruleName,
node: comment,
})
}
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 46.43% | (13 / 28) | 0% | (0 / 8) | 0% | (0 / 1) | 46.43% | (13 / 28) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const containsString = require("../../utils/containsString")
const matchesStringOrRegExp = require("../../utils/matchesStringOrRegExp")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "comment-word-blacklist"
const messages = ruleMessages(ruleName, {
rejected: pattern => `Unexpected word matching pattern "${pattern}"`,
})
const rule = function (blacklist) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: blacklist,
possible: [_.isString],
})
if (!validOptions) {
return
}
root.walkComments(comment => {
const text = comment.text
const rawComment = comment.toString()
const firstFourChars = rawComment.substr(0, 4)
// Return early if sourcemap
if (firstFourChars === "/*# ") {
return
}
const matchesWord = matchesStringOrRegExp(text, blacklist) || containsString(text, blacklist)
if (!matchesWord) {
return
}
report({
message: messages.rejected(matchesWord.pattern),
node: comment,
result,
ruleName,
})
})
}
}
rule.primaryOptionArray = true
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 47.83% | (11 / 23) | 0% | (0 / 8) | 0% | (0 / 1) | 47.83% | (11 / 23) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const atRuleParamIndex = require("../../utils/atRuleParamIndex")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "custom-media-pattern"
const messages = ruleMessages(ruleName, {
expected: "Expected custom media query name to match specified pattern",
})
const rule = function (pattern) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: pattern,
possible: [
_.isRegExp,
_.isString,
],
})
if (!validOptions) {
return
}
const regexpPattern = _.isString(pattern) ? new RegExp(pattern) : pattern
root.walkAtRules(atRule => {
if (atRule.name.toLowerCase() !== "custom-media") {
return
}
const customMediaName = atRule.params.match(/^--(\S+)\b/)[1]
if (regexpPattern.test(customMediaName)) {
return
}
report({
message: messages.expected,
node: atRule,
index: atRuleParamIndex(atRule),
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 36.59% | (15 / 41) | 0% | (0 / 36) | 0% | (0 / 1) | 36.59% | (15 / 41) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const blockString = require("../../utils/blockString")
const hasEmptyLine = require("../../utils/hasEmptyLine")
const isCustomProperty = require("../../utils/isCustomProperty")
const isSingleLineString = require("../../utils/isSingleLineString")
const isStandardSyntaxDeclaration = require("../../utils/isStandardSyntaxDeclaration")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "custom-property-empty-line-before"
const messages = ruleMessages(ruleName, {
expected: "Expected empty line before custom property",
rejected: "Unexpected empty line before custom property",
})
const rule = function (expectation, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
}, {
actual: options,
possible: {
except: [
"first-nested",
"after-comment",
"after-custom-property",
],
ignore: [
"after-comment",
"inside-single-line-block",
],
},
optional: true,
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const prop = decl.prop,
parent = decl.parent
if (!isStandardSyntaxDeclaration(decl)) {
return
}
if (!isCustomProperty(prop)) {
return
}
// Optionally ignore the node if a comment precedes it
if (
optionsMatches(options, "ignore", "after-comment")
&& decl.prev()
&& decl.prev().type === "comment"
) {
return
}
// Optionally ignore nodes inside single-line blocks
if (
optionsMatches(options, "ignore", "inside-single-line-block")
&& isSingleLineString(blockString(parent))
) {
return
}
let expectEmptyLineBefore = expectation === "always" ? true : false
// Optionally reverse the expectation for the first nested node
if (
optionsMatches(options, "except", "first-nested")
&& decl === parent.first
) {
expectEmptyLineBefore = !expectEmptyLineBefore
}
// Optionally reverse the expectation if a comment precedes this node
if (
optionsMatches(options, "except", "after-comment")
&& decl.prev()
&& decl.prev().type === "comment"
) {
expectEmptyLineBefore = !expectEmptyLineBefore
}
// Optionally reverse the expectation if a custom property precedes this node
if (
optionsMatches(options, "except", "after-custom-property")
&& decl.prev()
&& decl.prev().prop
&& isCustomProperty(decl.prev().prop)
) {
expectEmptyLineBefore = !expectEmptyLineBefore
}
const hasEmptyLineBefore = hasEmptyLine(decl.raws.before)
// Return if the expectation is met
if (expectEmptyLineBefore === hasEmptyLineBefore) {
return
}
const message = expectEmptyLineBefore ? messages.expected : messages.rejected
report({
message,
node: decl,
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 45.45% | (10 / 22) | 0% | (0 / 6) | 0% | (0 / 1) | 45.45% | (10 / 22) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isCustomProperty = require("../../utils/isCustomProperty")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "custom-property-no-outside-root"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected custom property",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
result.warn((
`'${ruleName}' has been deprecated and in 8.0 will be removed. Instead use the community 'stylelint-suitcss' plugin pack.`
), {
stylelintType: "deprecation",
stylelintReference: `https://stylelint.io/user-guide/rules/${ruleName}/`,
})
root.walkRules(rule => {
// Ignore rules whose selector is just `:root`
if (rule.selector.toLowerCase().trim() === ":root") {
return
}
rule.walkDecls(decl => {
if (!isCustomProperty(decl.prop)) {
return
}
report({
message: messages.rejected,
node: decl,
result,
ruleName,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 47.83% | (11 / 23) | 0% | (0 / 8) | 0% | (0 / 1) | 47.83% | (11 / 23) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const isCustomProperty = require("../../utils/isCustomProperty")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "custom-property-pattern"
const messages = ruleMessages(ruleName, {
expected: "Expected custom property name to match specified pattern",
})
const rule = function (pattern) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: pattern,
possible: [
_.isRegExp,
_.isString,
],
})
if (!validOptions) {
return
}
const regexpPattern = _.isString(pattern) ? new RegExp(pattern) : pattern
root.walkDecls(decl => {
const prop = decl.prop
if (!isCustomProperty(prop)) {
return
}
if (regexpPattern.test(prop.slice(2))) {
return
}
report({
message: messages.expected,
node: decl,
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 55.56% | (10 / 18) | 0% | (0 / 2) | 0% | (0 / 1) | 55.56% | (10 / 18) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const declarationBangSpaceChecker = require("../declarationBangSpaceChecker")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "declaration-bang-space-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected single space after \"!\"",
rejectedAfter: () => "Unexpected whitespace after \"!\"",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
declarationBangSpaceChecker({
root,
result,
locationChecker: checker.after,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 55.56% | (10 / 18) | 0% | (0 / 2) | 0% | (0 / 1) | 55.56% | (10 / 18) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const declarationBangSpaceChecker = require("../declarationBangSpaceChecker")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "declaration-bang-space-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected single space before \"!\"",
rejectedBefore: () => "Unexpected whitespace before \"!\"",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
declarationBangSpaceChecker({
root,
result,
locationChecker: checker.before,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 25.93% | (14 / 54) | 0% | (0 / 32) | 0% | (0 / 2) | 25.93% | (14 / 54) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const isCustomProperty = require("../../utils/isCustomProperty")
const isStandardSyntaxProperty = require("../../utils/isStandardSyntaxProperty")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "declaration-block-no-duplicate-properties"
const messages = ruleMessages(ruleName, {
rejected: property => `Unexpected duplicate "${property}"`,
})
const rule = function (on, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual: on }, {
actual: options,
possible: {
ignore: [
"consecutive-duplicates",
"consecutive-duplicates-with-different-values",
],
ignoreProperties: [_.isString],
},
optional: true,
})
if (!validOptions) {
return
}
// In order to accommodate nested blocks (postcss-nested),
// we need to run a shallow loop (instead of eachDecl() or eachRule(),
// which loop recursively) and allow each nested block to accumulate
// its own list of properties -- so that a property in a nested rule
// does not conflict with the same property in the parent rule
root.each(node => {
if (
node.type === "rule"
|| node.type === "atrule"
) {
checkRulesInNode(node)
}
})
function checkRulesInNode(node) {
const decls = []
const values = []
node.each(child => {
if (
child.nodes
&& child.nodes.length
) {
checkRulesInNode(child)
}
if (child.type !== "decl") {
return
}
const prop = child.prop
const value = child.value
if (!isStandardSyntaxProperty(prop)) {
return
}
if (isCustomProperty(prop)) {
return
}
// Return early if the property is to be ignored
if (optionsMatches(options, "ignoreProperties", prop)) {
return
}
// Ignore the src property as commonly duplicated in at-fontface
if (prop.toLowerCase() === "src") {
return
}
const indexDuplicate = decls.indexOf(prop.toLowerCase())
if (indexDuplicate !== -1) {
if (optionsMatches(options, "ignore", "consecutive-duplicates-with-different-values")) {
// if duplicates are not consecutive
if (indexDuplicate !== decls.length - 1) {
report({
message: messages.rejected(prop),
node: child,
result,
ruleName,
})
return
}
// if values of consecutive duplicates are equal
if (value === values[indexDuplicate]) {
report({
message: messages.rejected(value),
node: child,
result,
ruleName,
})
return
}
return
}
if (
optionsMatches(options, "ignore", "consecutive-duplicates")
&& indexDuplicate === decls.length - 1
) {
return
}
report({
message: messages.rejected(prop),
node: child,
result,
ruleName,
})
}
decls.push(prop.toLowerCase())
values.push(value.toLowerCase())
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 34.29% | (12 / 35) | 0% | (0 / 11) | 0% | (0 / 1) | 34.29% | (12 / 35) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const matchesStringOrRegExp = require("../../utils/matchesStringOrRegExp")
const postcss = require("postcss")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "declaration-block-no-ignored-properties"
const messages = ruleMessages(ruleName, {
rejected: (ignored, cause) => `Unexpected "${ignored}" with "${cause}"`,
})
const ignored = [
{
property: "display",
value: "inline",
ignoredProperties: [
"width",
"min-width",
"max-width",
"height",
"min-height",
"max-height",
"margin",
"margin-top",
"margin-bottom",
"overflow",
"overflow-x",
"overflow-y",
],
},
{
property: "display",
value: "list-item",
ignoredProperties: ["vertical-align"],
},
{
property: "display",
value: "block",
ignoredProperties: ["vertical-align"],
},
{
property: "display",
value: "flex",
ignoredProperties: ["vertical-align"],
},
{
property: "display",
value: "table",
ignoredProperties: ["vertical-align"],
},
{
property: "display",
value: "/^table-.*$/",
ignoredProperties: [
"margin",
"margin-top",
"margin-right",
"margin-bottom",
"margin-left",
],
},
{
property: "display",
value: "/^table-(row|row-group|column|column-group|header-group|footer-group|caption).*$/",
ignoredProperties: ["vertical-align"],
},
{
property: "display",
value: "/^table-(row|row-group).*$/",
ignoredProperties: [
"width",
"min-width",
"max-width",
],
},
{
property: "display",
value: "/^table-(column|column-group).*$/",
ignoredProperties: [
"height",
"min-height",
"max-height",
],
},
{
property: "float",
value: "left",
ignoredProperties: ["vertical-align"],
},
{
property: "float",
value: "right",
ignoredProperties: ["vertical-align"],
},
{
property: "position",
value: "static",
ignoredProperties: [
"top",
"right",
"bottom",
"left",
],
},
{
property: "position",
value: "absolute",
ignoredProperties: [
"float",
"clear",
"vertical-align",
],
},
{
property: "position",
value: "fixed",
ignoredProperties: [
"float",
"clear",
"vertical-align",
],
},
]
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
result.warn((
"'declaration-block-no-ignored-properties' has been deprecated and in 8.0 will be removed."
), {
stylelintType: "deprecation",
stylelintReference: "https://stylelint.io/user-guide/rules/declaration-block-no-ignored-properties/",
})
const uniqueDecls = {}
root.walkDecls(decl => {
uniqueDecls[decl.prop] = decl
})
Object.keys(uniqueDecls).forEach((prop, index) => {
const decl = uniqueDecls[prop]
const unprefixedProp = postcss.vendor.unprefixed(prop)
const unprefixedValue = postcss.vendor.unprefixed(decl.value)
ignored.forEach(ignore => {
const matchProperty = matchesStringOrRegExp(unprefixedProp.toLowerCase(), ignore.property)
const matchValue = matchesStringOrRegExp(unprefixedValue.toLowerCase(), ignore.value)
if (!matchProperty || !matchValue) {
return
}
const ignoredProperties = ignore.ignoredProperties
decl.parent.nodes.forEach((node, nodeIndex) => {
if (!node.prop || ignoredProperties.indexOf(node.prop.toLowerCase()) === -1 || index === nodeIndex) {
return
}
report({
message: messages.rejected(node.prop, decl.toString()),
node,
result,
ruleName,
})
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 34.21% | (13 / 38) | 0% | (0 / 14) | 0% | (0 / 2) | 34.21% | (13 / 38) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const shorthandData = require("../../reference/shorthandData")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "declaration-block-no-redundant-longhand-properties"
const messages = ruleMessages(ruleName, {
expected: props => `Expected shorthand property "${props}"`,
})
const rule = function (actual, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual }, {
actual: options,
possible: {
ignoreShorthands: [_.isString],
},
optional: true,
})
if (!validOptions) {
return
}
const longhandProperties = _.transform(shorthandData, (result, values, key) => {
if (optionsMatches(options, "ignoreShorthands", key)) {
return
}
values.forEach(value => {
(result[value] || (result[value] = [])).push(key)
})
})
root.walkRules(check)
root.walkAtRules(check)
function check(statement) {
const longhandDeclarations = {}
// Shallow iteration so nesting doesn't produce
// false positives
statement.each(node => {
if (node.type !== "decl") {
return
}
const prop = node.prop.toLowerCase()
const shorthandProperties = longhandProperties[prop]
if (!shorthandProperties) {
return
}
shorthandProperties.forEach(shorthandProperty => {
(longhandDeclarations[shorthandProperty] || (longhandDeclarations[shorthandProperty] = [])).push(prop)
if (!_.isEqual(shorthandData[shorthandProperty].sort(), longhandDeclarations[shorthandProperty].sort())) {
return
}
report({
ruleName,
result,
node,
message: messages.expected(shorthandProperty),
})
})
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 35.48% | (11 / 31) | 0% | (0 / 8) | 0% | (0 / 2) | 35.48% | (11 / 31) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const shorthandData = require("../../reference/shorthandData")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "declaration-block-no-shorthand-property-overrides"
const messages = ruleMessages(ruleName, {
rejected: (shorthand, original) => `Unexpected shorthand "${shorthand}" after "${original}"`,
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkRules(check)
root.walkAtRules(check)
function check(statement) {
const declarations = {}
// Shallow iteration so nesting doesn't produce
// false positives
statement.each(node => {
if (node.type !== "decl") {
return
}
const prop = node.prop
const overrideables = shorthandData[prop.toLowerCase()]
if (!overrideables) {
declarations[prop.toLowerCase()] = prop
return
}
overrideables.forEach(longhandProp => {
if (!declarations.hasOwnProperty(longhandProp)) {
return
}
report({
ruleName,
result,
node,
message: messages.rejected(prop, declarations[longhandProp]),
})
})
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 17.29% | (23 / 133) | 0% | (0 / 114) | 0% | (0 / 10) | 17.56% | (23 / 131) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isCustomProperty = require("../../utils/isCustomProperty")
const isStandardSyntaxProperty = require("../../utils/isStandardSyntaxProperty")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const postcss = require("postcss")
const ruleName = "declaration-block-properties-order"
const messages = ruleMessages(ruleName, {
expected: (first, second) => `Expected "${first}" to come before "${second}"`,
})
const rule = function (expectation, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: validatePrimaryOption,
}, {
actual: options,
possible: {
unspecified: [
"top",
"bottom",
"ignore",
"bottomAlphabetical",
],
},
optional: true,
})
if (!validOptions) {
return
}
result.warn((
"'declaration-block-properties-order'has been deprecated and in 8.0 will be removed. " +
"Instead use the community 'stylelint-order' plugin pack."
), {
stylelintType: "deprecation",
stylelintReference: "https://stylelint.io/user-guide/rules/declaration-block-properties-order/",
})
const alphabetical = expectation === "alphabetical"
const expectedOrder = alphabetical ? null : createExpectedOrder(expectation)
// By default, ignore unspecified properties
const unspecified = _.get(options, ["unspecified"], "ignore")
// Shallow loop
root.each(node => {
if (node.type === "rule" || node.type === "atrule") {
checkNode(node)
}
})
function checkNode(node) {
const allPropData = []
node.each(child => {
// If the child has nested nodes with child
// (e.g. a rule nested within a rule), make
// sure to check the children
if (child.nodes && child.nodes.length) {
checkNode(child)
}
if (child.type !== "decl") {
return
}
const prop = child.prop
if (!isStandardSyntaxProperty(prop)) {
return
}
if (isCustomProperty(prop)) {
return
}
let unprefixedPropName = postcss.vendor.unprefixed(prop)
// Hack to allow -moz-osx-font-smoothing to be understood
// just like -webkit-font-smoothing
if (unprefixedPropName.indexOf("osx-") === 0) {
unprefixedPropName = unprefixedPropName.slice(4)
}
const propData = {
name: prop,
unprefixedName: unprefixedPropName,
orderData: alphabetical ? null : getOrderData(expectedOrder, unprefixedPropName),
before: child.raws.before,
index: allPropData.length,
node: child,
}
const previousPropData = _.last(allPropData)
allPropData.push(propData)
// Skip first decl
if (!previousPropData) {
return
}
const isCorrectOrder = alphabetical ? checkAlpabeticalOrder(previousPropData, propData) : checkOrder(previousPropData, propData)
if (isCorrectOrder) {
return
}
complain({
message: messages.expected(propData.name, previousPropData.name),
node: child,
})
})
function checkOrder(firstPropData, secondPropData) {
// If the unprefixed property names are the same, resort to alphabetical ordering
if (firstPropData.unprefixedName === secondPropData.unprefixedName) {
return firstPropData.name <= secondPropData.name
}
const firstPropIsUnspecified = !firstPropData.orderData
const secondPropIsUnspecified = !secondPropData.orderData
// Now check actual known properties ...
if (!firstPropIsUnspecified && !secondPropIsUnspecified) {
return firstPropData.orderData.expectedPosition <= secondPropData.orderData.expectedPosition
}
if (firstPropIsUnspecified && !secondPropIsUnspecified) {
// If first prop is unspecified, look for a specified prop before it to
// compare to the current prop
const priorSpecifiedPropData = _.findLast(allPropData.slice(0, -1), d => !!d.orderData)
if (priorSpecifiedPropData && priorSpecifiedPropData.orderData && priorSpecifiedPropData.orderData.expectedPosition > secondPropData.orderData.expectedPosition) {
complain({
message: messages.expected(secondPropData.name, priorSpecifiedPropData.name),
node: secondPropData.node,
})
return true // avoid logging another warning
}
}
// Now deal with unspecified props ...
// Starting with bottomAlphabetical as it requires more specific conditionals
if (unspecified === "bottomAlphabetical" && !firstPropIsUnspecified && secondPropIsUnspecified) {
return true
}
if (unspecified === "bottomAlphabetical" && secondPropIsUnspecified && firstPropIsUnspecified) {
if (checkAlpabeticalOrder(firstPropData, secondPropData)) {
return true
} else {
return false
}
}
if (unspecified === "bottomAlphabetical" && firstPropIsUnspecified) {
return false
}
if (firstPropIsUnspecified && secondPropIsUnspecified) {
return true
}
if (unspecified === "ignore" && (firstPropIsUnspecified || secondPropIsUnspecified)) {
return true
}
if (unspecified === "top" && firstPropIsUnspecified) {
return true
}
if (unspecified === "top" && secondPropIsUnspecified) {
return false
}
if (unspecified === "bottom" && secondPropIsUnspecified) {
return true
}
if (unspecified === "bottom" && firstPropIsUnspecified) {
return false
}
}
}
function complain(opts) {
report({
message: opts.message,
node: opts.node,
result,
ruleName,
})
}
}
}
rule.primaryOptionArray = true
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
function createExpectedOrder(input) {
const order = {}
let expectedPosition = 0
appendGroup(input)
function appendGroup(items) {
items.forEach(item => appendItem(item, false))
}
function appendItem(item, inFlexibleGroup) {
if (_.isString(item)) {
// In flexible groups, the expectedPosition does not ascend
// to make that flexibility work;
// otherwise, it will always ascend
if (!inFlexibleGroup) {
expectedPosition += 1
}
order[item] = { expectedPosition }
return
}
if (!item.order || item.order === "strict") {
appendGroup(item.properties)
return
} else if (item.order === "flexible") {
expectedPosition += 1
item.properties.forEach(property => {
appendItem(property, true)
})
}
}
return order
}
function getOrderData(expectedOrder, propName) {
let orderData = expectedOrder[propName]
// If prop was not specified but has a hyphen
// (e.g. `padding-top`), try looking for the segment preceding the hyphen
// and use that index
if (!orderData && propName.lastIndexOf("-") !== -1) {
const propNamePreHyphen = propName.slice(0, propName.lastIndexOf("-"))
orderData = getOrderData(expectedOrder, propNamePreHyphen)
}
return orderData
}
function checkAlpabeticalOrder(firstPropData, secondPropData) {
// If unprefixed prop names are the same, compare the prefixed versions
if (firstPropData.unprefixedName === secondPropData.unprefixedName) {
return firstPropData.name <= secondPropData.name
}
return firstPropData.unprefixedName < secondPropData.unprefixedName
}
function validatePrimaryOption(actualOptions) {
// Return true early if alphabetical
if (actualOptions === "alphabetical") {
return true
}
// Otherwise, begin checking array options
if (!Array.isArray(actualOptions)) {
return false
}
// Every item in the array must be a string or an object
// with a "properties" property
if (!actualOptions.every(item => {
if (_.isString(item)) {
return true
}
return _.isPlainObject(item) && !_.isUndefined(item.properties)
})) {
return false
}
const objectItems = actualOptions.filter(_.isPlainObject)
// Every object-item's "order" property must be "strict" or "flexible"
if (!objectItems.every(item => {
if (_.isUndefined(item.order)) {
return true
}
return _.includes([
"strict",
"flexible",
], item.order)
})) {
return false
}
return true
}
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 39.39% | (13 / 33) | 0% | (0 / 10) | 0% | (0 / 1) | 39.39% | (13 / 33) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const blockString = require("../../utils/blockString")
const nextNonCommentNode = require("../../utils/nextNonCommentNode")
const rawNodeString = require("../../utils/rawNodeString")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "declaration-block-semicolon-newline-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected newline after \";\"",
expectedAfterMultiLine: () => "Expected newline after \";\" in a multi-line declaration block",
rejectedAfterMultiLine: () => "Unexpected newline after \";\" in a multi-line declaration block",
})
const rule = function (expectation) {
const checker = whitespaceChecker("newline", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"always-multi-line",
"never-multi-line",
],
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
// Ignore last declaration if there's no trailing semicolon
const parentRule = decl.parent
if (
!parentRule.raws.semicolon
&& parentRule.last === decl
) {
return
}
const nextNode = decl.next()
if (!nextNode) {
return
}
// Allow end-of-line comment
const nodeToCheck = nextNonCommentNode(nextNode)
if (!nodeToCheck) {
return
}
checker.afterOneOnly({
source: rawNodeString(nodeToCheck),
index: -1,
lineCheckStr: blockString(parentRule),
err: m => {
report({
message: m,
node: decl,
index: decl.toString().length + 1,
result,
ruleName,
})
},
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 42.31% | (11 / 26) | 0% | (0 / 6) | 0% | (0 / 3) | 42.31% | (11 / 26) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const blockString = require("../../utils/blockString")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "declaration-block-semicolon-newline-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected newline before \";\"",
expectedBeforeMultiLine: () => "Expected newline before \";\" in a multi-line declaration block",
rejectedBeforeMultiLine: () => "Unexpected whitespace before \";\" in a multi-line declaration block",
})
const rule = function (expectation) {
const checker = whitespaceChecker("newline", expectation, messages)
return function (root, result) {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"always-multi-line",
"never-multi-line",
],
})
if (!validOptions) {
return
}
root.walkDecls(function (decl) {
const parentRule = decl.parent
if (
!parentRule.raws.semicolon
&& parentRule.last === decl
) {
return
}
const declString = decl.toString()
checker.beforeAllowingIndentation({
source: declString,
index: declString.length,
lineCheckStr: blockString(parentRule),
err: m => {
report({
message: m,
node: decl,
index: decl.toString().length - 1,
result,
ruleName,
})
},
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 40% | (12 / 30) | 0% | (0 / 8) | 0% | (0 / 3) | 40% | (12 / 30) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const blockString = require("../../utils/blockString")
const rawNodeString = require("../../utils/rawNodeString")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "declaration-block-semicolon-space-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected single space after \";\"",
rejectedAfter: () => "Unexpected whitespace after \";\"",
expectedAfterSingleLine: () => "Expected single space after \";\" in a single-line declaration block",
rejectedAfterSingleLine: () => "Unexpected whitespace after \";\" in a single-line declaration block",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return function (root, result) {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-single-line",
"never-single-line",
],
})
if (!validOptions) {
return
}
root.walkDecls(function (decl) {
// Ignore last declaration if there's no trailing semicolon
const parentRule = decl.parent
if (!parentRule.raws.semicolon && parentRule.last === decl) {
return
}
const nextDecl = decl.next()
if (!nextDecl) {
return
}
checker.after({
source: rawNodeString(nextDecl),
index: -1,
lineCheckStr: blockString(parentRule),
err: m => {
report({
message: m,
node: decl,
index: decl.toString().length + 1,
result,
ruleName,
})
},
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 40.74% | (11 / 27) | 0% | (0 / 6) | 0% | (0 / 1) | 40.74% | (11 / 27) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const blockString = require("../../utils/blockString")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "declaration-block-semicolon-space-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected single space before \";\"",
rejectedBefore: () => "Unexpected whitespace before \";\"",
expectedBeforeSingleLine: () => "Expected single space before \";\" in a single-line declaration block",
rejectedBeforeSingleLine: () => "Unexpected whitespace before \";\" in a single-line declaration block",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-single-line",
"never-single-line",
],
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
// Ignore last declaration if there's no trailing semicolon
const parentRule = decl.parent
if (!parentRule.raws.semicolon && parentRule.last === decl) {
return
}
const declString = decl.toString()
checker.before({
source: declString,
index: declString.length,
lineCheckStr: blockString(parentRule),
err: m => {
report({
message: m,
node: decl,
index: decl.toString().length - 1,
result,
ruleName,
})
},
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 46.43% | (13 / 28) | 0% | (0 / 8) | 0% | (0 / 1) | 48.15% | (13 / 27) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const beforeBlockString = require("../../utils/beforeBlockString")
const blockString = require("../../utils/blockString")
const isSingleLineString = require("../../utils/isSingleLineString")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const ruleName = "declaration-block-single-line-max-declarations"
const messages = ruleMessages(ruleName, {
expected: quantity => `Expected no more than ${quantity} declaration(s)`,
})
const rule = function (quantity) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: quantity,
possible: [_.isNumber],
})
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isSingleLineString(blockString(rule))) {
return
}
if (!rule.nodes) {
return
}
const decls = rule.nodes.filter(node => node.type === "decl")
if (decls.length <= quantity) {
return
}
report({
message: messages.expected(quantity),
node: rule,
index: beforeBlockString(rule, { noRawBefore: true }).length,
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 29.73% | (11 / 37) | 0% | (0 / 18) | 0% | (0 / 2) | 29.73% | (11 / 37) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const hasBlock = require("../../utils/hasBlock")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "declaration-block-trailing-semicolon"
const messages = ruleMessages(ruleName, {
expected: "Expected a trailing semicolon",
rejected: "Unexpected trailing semicolon",
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
root.walkAtRules(atRule => {
if (atRule.parent === root) {
return
}
if (atRule !== atRule.parent.last) {
return
}
if (hasBlock(atRule)) {
return
}
checkLastNode(atRule)
})
root.walkDecls(decl => {
if (decl !== decl.parent.last) {
return
}
checkLastNode(decl)
})
function checkLastNode(node) {
let message
if (expectation === "always") {
if (node.parent.raws.semicolon) {
return
}
message = messages.expected
}
if (expectation === "never") {
if (!node.parent.raws.semicolon) {
return
}
message = messages.rejected
}
report({
message,
node,
index: node.toString().trim().length - 1,
result,
ruleName,
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 40% | (12 / 30) | 0% | (0 / 10) | 0% | (0 / 1) | 40% | (12 / 30) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const declarationValueIndex = require("../../utils/declarationValueIndex")
const isStandardSyntaxDeclaration = require("../../utils/isStandardSyntaxDeclaration")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const ruleName = "declaration-colon-newline-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected newline after \":\"",
expectedAfterMultiLine: () => "Expected newline after \":\" with a multi-line declaration",
})
const rule = function (expectation) {
const checker = whitespaceChecker("newline", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"always-multi-line",
],
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
if (!isStandardSyntaxDeclaration(decl)) {
return
}
// Get the raw prop, and only the prop
const endOfPropIndex = declarationValueIndex(decl) + (decl.raws.between || "").length - 1
// The extra characters tacked onto the end ensure that there is a character to check
// after the colon. Otherwise, with `background:pink` the character after the
const propPlusColon = decl.toString().slice(0, endOfPropIndex) + "xxx"
for (let i = 0, l = propPlusColon.length; i < l; i++) {
if (propPlusColon[i] !== ":") {
continue
}
const indexToCheck = propPlusColon.substr(propPlusColon[i], 3) === "/*" ? propPlusColon.indexOf("*/", i) + 1 : i
checker.afterOneOnly({
source: propPlusColon,
index: indexToCheck,
lineCheckStr: decl.value,
err: m => {
report({
message: m,
node: decl,
index: indexToCheck,
result,
ruleName,
})
},
})
}
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 52.63% | (10 / 19) | 0% | (0 / 2) | 0% | (0 / 1) | 52.63% | (10 / 19) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const declarationColonSpaceChecker = require("../declarationColonSpaceChecker")
const ruleName = "declaration-colon-space-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected single space after \":\"",
rejectedAfter: () => "Unexpected whitespace after \":\"",
expectedAfterSingleLine: () => "Expected single space after \":\" with a single-line declaration",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-single-line",
],
})
if (!validOptions) {
return
}
declarationColonSpaceChecker({
root,
result,
locationChecker: checker.after,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 55.56% | (10 / 18) | 0% | (0 / 2) | 0% | (0 / 1) | 55.56% | (10 / 18) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const declarationColonSpaceChecker = require("../declarationColonSpaceChecker")
const ruleName = "declaration-colon-space-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected single space before \":\"",
rejectedBefore: () => "Unexpected whitespace before \":\"",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
declarationColonSpaceChecker({
root,
result,
locationChecker: checker.before,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 34.88% | (15 / 43) | 0% | (0 / 42) | 0% | (0 / 1) | 34.88% | (15 / 43) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const blockString = require("../../utils/blockString")
const hasEmptyLine = require("../../utils/hasEmptyLine")
const isCustomProperty = require("../../utils/isCustomProperty")
const isSingleLineString = require("../../utils/isSingleLineString")
const isStandardSyntaxDeclaration = require("../../utils/isStandardSyntaxDeclaration")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "declaration-empty-line-before"
const messages = ruleMessages(ruleName, {
expected: "Expected empty line before declaration",
rejected: "Unexpected empty line before declaration",
})
const rule = function (expectation, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
}, {
actual: options,
possible: {
except: [
"first-nested",
"after-comment",
"after-declaration",
],
ignore: [
"after-comment",
"after-declaration",
"inside-single-line-block",
],
},
optional: true,
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const prop = decl.prop,
parent = decl.parent
if (!isStandardSyntaxDeclaration(decl)) {
return
}
if (isCustomProperty(prop)) {
return
}
// Optionally ignore the node if a comment precedes it
if (
optionsMatches(options, "ignore", "after-comment")
&& decl.prev()
&& decl.prev().type === "comment"
) {
return
}
// Optionally ignore the node if a declaration precedes it
if (
optionsMatches(options, "ignore", "after-declaration")
&& decl.prev()
&& decl.prev().type === "decl"
) {
return
}
// Optionally ignore nodes inside single-line blocks
if (
optionsMatches(options, "ignore", "inside-single-line-block")
&& isSingleLineString(blockString(parent))
) {
return
}
let expectEmptyLineBefore = expectation === "always"
? true
: false
// Optionally reverse the expectation for the first nested node
if (
optionsMatches(options, "except", "first-nested")
&& decl === parent.first
) {
expectEmptyLineBefore = !expectEmptyLineBefore
}
// Optionally reverse the expectation if a comment precedes this node
if (
optionsMatches(options, "except", "after-comment")
&& decl.prev()
&& decl.prev().type === "comment"
) {
expectEmptyLineBefore = !expectEmptyLineBefore
}
// Optionally reverse the expectation if a declaration precedes this node
if (
optionsMatches(options, "except", "after-declaration")
&& decl.prev()
&& decl.prev().prop
&& isStandardSyntaxDeclaration(decl.prev())
&& !isCustomProperty(decl.prev().prop)
) {
expectEmptyLineBefore = !expectEmptyLineBefore
}
// Check for at least one empty line
const hasEmptyLineBefore = hasEmptyLine(decl.raws.before)
// Return if the expectation is met
if (expectEmptyLineBefore === hasEmptyLineBefore) {
return
}
const message = expectEmptyLineBefore
? messages.expected
: messages.rejected
report({ message, node: decl, result, ruleName })
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 52.94% | (9 / 17) | 0% | (0 / 4) | 0% | (0 / 1) | 52.94% | (9 / 17) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | 1 1 1 1 1 1 1 1 1 | "use strict"
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "declaration-no-important"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected !important",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkDecls(decl => {
if (!decl.important) {
return
}
report({
message: messages.rejected,
node: decl,
word: "important",
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 41.67% | (15 / 36) | 0% | (0 / 15) | 0% | (0 / 2) | 42.86% | (15 / 35) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const declarationValueIndex = require("../../utils/declarationValueIndex")
const getUnitFromValueNode = require("../../utils/getUnitFromValueNode")
const matchesStringOrRegExp = require("../../utils/matchesStringOrRegExp")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const valueParser = require("postcss-value-parser")
const postcss = require("postcss")
const ruleName = "declaration-property-unit-blacklist"
const messages = ruleMessages(ruleName, {
rejected: (property, unit) => `Unexpected unit "${unit}" for property "${property}"`,
})
const rule = function (blacklist) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: blacklist,
possible: [_.isObject],
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const prop = decl.prop,
value = decl.value
const unprefixedProp = postcss.vendor.unprefixed(prop)
const propBlacklist = _.find(blacklist, (list, propIdentifier) => matchesStringOrRegExp(unprefixedProp, propIdentifier))
if (!propBlacklist) {
return
}
valueParser(value).walk(function (node) {
// Ignore wrong units within `url` function
if (
node.type === "function"
&& node.value.toLowerCase() === "url"
) {
return false
}
if (node.type === "string") {
return
}
const unit = getUnitFromValueNode(node)
if (
!unit
|| unit
&& propBlacklist.indexOf(unit.toLowerCase()) === -1
) {
return
}
report({
message: messages.rejected(prop, unit),
node: decl,
index: declarationValueIndex(decl) + node.sourceIndex,
result,
ruleName,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 41.67% | (15 / 36) | 0% | (0 / 16) | 0% | (0 / 2) | 42.86% | (15 / 35) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const declarationValueIndex = require("../../utils/declarationValueIndex")
const getUnitFromValueNode = require("../../utils/getUnitFromValueNode")
const matchesStringOrRegExp = require("../../utils/matchesStringOrRegExp")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const valueParser = require("postcss-value-parser")
const postcss = require("postcss")
const ruleName = "declaration-property-unit-whitelist"
const messages = ruleMessages(ruleName, {
rejected: (property, unit) => `Unexpected unit "${unit}" for property "${property}"`,
})
const rule = function (whitelist) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: whitelist,
possible: [_.isObject],
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const prop = decl.prop,
value = decl.value
const unprefixedProp = postcss.vendor.unprefixed(prop)
const propWhitelist = _.find(whitelist, (list, propIdentifier) => matchesStringOrRegExp(unprefixedProp, propIdentifier))
if (!propWhitelist) {
return
}
valueParser(value).walk(function (node) {
// Ignore wrong units within `url` function
if (node.type === "function" && node.value.toLowerCase() === "url") {
return false
}
if (node.type === "string") {
return
}
const unit = getUnitFromValueNode(node)
if (!unit || (unit && propWhitelist.indexOf(unit.toLowerCase())) !== -1) {
return
}
report({
message: messages.rejected(prop, unit),
node: decl,
index: declarationValueIndex(decl) + node.sourceIndex,
result,
ruleName,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 44.44% | (12 / 27) | 0% | (0 / 6) | 0% | (0 / 1) | 46.15% | (12 / 26) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const matchesStringOrRegExp = require("../../utils/matchesStringOrRegExp")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const postcss = require("postcss")
const ruleName = "declaration-property-value-blacklist"
const messages = ruleMessages(ruleName, {
rejected: (property, value) => `Unexpected value "${value}" for property "${property}"`,
})
const rule = function (blacklist) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: blacklist,
possible: [_.isObject],
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const prop = decl.prop,
value = decl.value
const unprefixedProp = postcss.vendor.unprefixed(prop)
const propBlacklist = _.find(blacklist, (list, propIdentifier) => matchesStringOrRegExp(unprefixedProp, propIdentifier))
if (_.isEmpty(propBlacklist)) {
return
}
if (!matchesStringOrRegExp(value, propBlacklist)) {
return
}
report({
message: messages.rejected(prop, value),
node: decl,
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 44.44% | (12 / 27) | 0% | (0 / 6) | 0% | (0 / 1) | 46.15% | (12 / 26) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const matchesStringOrRegExp = require("../../utils/matchesStringOrRegExp")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const postcss = require("postcss")
const ruleName = "declaration-property-value-whitelist"
const messages = ruleMessages(ruleName, {
rejected: (property, value) => `Unexpected value "${value}" for property "${property}"`,
})
const rule = function (whitelist) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: whitelist,
possible: [_.isObject],
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const prop = decl.prop,
value = decl.value
const unprefixedProp = postcss.vendor.unprefixed(prop)
const propWhitelist = _.find(whitelist, (list, propIdentifier) => matchesStringOrRegExp(unprefixedProp, propIdentifier))
if (_.isEmpty(propWhitelist)) {
return
}
if (matchesStringOrRegExp(value, propWhitelist)) {
return
}
report({
message: messages.rejected(prop, value),
node: decl,
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 26.47% | (18 / 68) | 0% | (0 / 45) | 0% | (0 / 6) | 26.47% | (18 / 68) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const findFontFamily = require("../../utils/findFontFamily")
const isStandardSyntaxValue = require("../../utils/isStandardSyntaxValue")
const isVariable = require("../../utils/isVariable")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const keywordSets = require("../../reference/keywordSets")
const ruleName = "font-family-name-quotes"
const messages = ruleMessages(ruleName, {
expected: family => `Expected quotes around "${family}"`,
rejected: family => `Unexpected quotes around "${family}"`,
})
function isSystemFontKeyword(font) {
if (font.indexOf("-apple-") === 0) {
return true
}
if (font === "BlinkMacSystemFont") {
return true
}
return false
}
// "To avoid mistakes in escaping, it is recommended to quote font family names
// that contain white space, digits, or punctuation characters other than hyphens"
// (https://www.w3.org/TR/CSS2/fonts.html#font-family-prop)
function quotesRecommended(family) {
return !/^[-a-zA-Z]+$/.test(family)
}
// Quotes are required if the family is not a valid CSS identifier
// (regexes from https://mathiasbynens.be/notes/unquoted-font-family)
function quotesRequired(family) {
return family.split(/\s+/).some(word => {
return (/^(-?\d|--)/.test(word) || !/^[-_a-zA-Z0-9\u00A0-\u10FFFF]+$/.test(word)
)
})
}
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always-where-required",
"always-where-recommended",
"always-unless-keyword",
],
})
if (!validOptions) {
return
}
root.walkDecls(/^font(-family)?$/i, decl => {
const fontFamilies = findFontFamily(decl.value)
if (fontFamilies.length === 0) {
return
}
fontFamilies.forEach(fontFamilyNode => {
let rawFamily = fontFamilyNode.value
if (fontFamilyNode.quote) {
rawFamily = fontFamilyNode.quote + rawFamily + fontFamilyNode.quote
}
checkFamilyName(rawFamily, decl)
})
})
function checkFamilyName(rawFamily, decl) {
if (!isStandardSyntaxValue(rawFamily)) {
return
}
if (isVariable(rawFamily)) {
return
}
const hasQuotes = rawFamily[0] === "'" || rawFamily[0] === "\""
// Clean the family of its quotes
const family = rawFamily.replace(/^['"]|['"]$/g, "")
// Disallow quotes around (case-insensitive) keywords
// and system font keywords in all cases
if (keywordSets.fontFamilyKeywords.has(family.toLowerCase()) || isSystemFontKeyword(family)) {
if (hasQuotes) {
return complain(messages.rejected(family), family, decl)
}
return
}
const required = quotesRequired(family)
const recommended = quotesRecommended(family)
switch (expectation) {
case "always-unless-keyword":
if (!hasQuotes) {
return complain(messages.expected(family), family, decl)
}
return
case "always-where-recommended":
if (!recommended && hasQuotes) {
return complain(messages.rejected(family), family, decl)
}
if (recommended && !hasQuotes) {
return complain(messages.expected(family), family, decl)
}
return
case "always-where-required":
if (!required && hasQuotes) {
return complain(messages.rejected(family), family, decl)
}
if (required && !hasQuotes) {
return complain(messages.expected(family), family, decl)
}
return
}
}
function complain(message, family, decl) {
report({
result,
ruleName,
message,
node: decl,
word: family,
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 37.21% | (16 / 43) | 0% | (0 / 14) | 0% | (0 / 2) | 38.1% | (16 / 42) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const declarationValueIndex = require("../../utils/declarationValueIndex")
const findFontFamily = require("../../utils/findFontFamily")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const keywordSets = require("../../reference/keywordSets")
const _ = require("lodash")
const optionsMatches = require("../../utils/optionsMatches")
const ruleName = "font-family-no-duplicate-names"
const messages = ruleMessages(ruleName, {
rejected: name => `Unexpected duplicate name ${name}`,
})
const isFamilyNameKeyword = node => !node.quote && keywordSets.fontFamilyKeywords.has(node.value.toLowerCase())
const rule = function (actual, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual }, {
actual: options,
possible: {
ignoreFontFamilyNames: [_.isString],
},
optional: true,
})
if (!validOptions) {
return
}
root.walkDecls(/^font(-family)?$/i, decl => {
const keywords = new Set()
const familyNames = new Set()
const fontFamilies = findFontFamily(decl.value)
if (fontFamilies.length === 0) {
return
}
fontFamilies.forEach(fontFamilyNode => {
const family = fontFamilyNode.value.trim()
if (optionsMatches(options, "ignoreFontFamilyNames", fontFamilyNode.value.trim())) {
return
}
if (isFamilyNameKeyword(fontFamilyNode)) {
if (keywords.has(family.toLowerCase())) {
complain(messages.rejected(family), declarationValueIndex(decl) + fontFamilyNode.sourceIndex, decl)
return
}
keywords.add(family)
return
}
if (familyNames.has(family)) {
complain(messages.rejected(family), declarationValueIndex(decl) + fontFamilyNode.sourceIndex, decl)
return
}
familyNames.add(family)
})
})
function complain(message, index, decl) {
report({
result,
ruleName,
message,
node: decl,
index,
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 38.71% | (24 / 62) | 0% | (0 / 39) | 0% | (0 / 4) | 38.71% | (24 / 62) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const declarationValueIndex = require("../../utils/declarationValueIndex")
const isNumbery = require("../../utils/isNumbery")
const isStandardSyntaxValue = require("../../utils/isStandardSyntaxValue")
const isVariable = require("../../utils/isVariable")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const keywordSets = require("../../reference/keywordSets")
const _ = require("lodash")
const postcss = require("postcss")
const ruleName = "font-weight-notation"
const messages = ruleMessages(ruleName, {
expected: type => `Expected ${type} font-weight notation`,
invalidNamed: name => `Unexpected invalid font-weight name "${name}"`,
})
const INHERIT_KEYWORD = "inherit"
const INITIAL_KEYWORD = "initial"
const NORMAL_KEYWORD = "normal"
const WEIGHTS_WITH_KEYWORD_EQUIVALENTS = [
"400",
"700",
]
const rule = function (expectation, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"numeric",
"named-where-possible",
],
}, {
actual: options,
possible: {
ignore: ["relative"],
},
optional: true,
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
if (decl.prop.toLowerCase() === "font-weight") {
checkWeight(decl.value, decl)
}
if (decl.prop.toLowerCase() === "font") {
checkFont(decl)
}
})
function checkFont(decl) {
const valueList = postcss.list.space(decl.value)
// We do not need to more carefully distinguish font-weight
// numbers from unitless line-heights because line-heights in
// `font` values need to be part of a font-size/line-height pair
const hasNumericFontWeight = valueList.some(isNumbery)
for (const value of postcss.list.space(decl.value)) {
if (value.toLowerCase() === NORMAL_KEYWORD && !hasNumericFontWeight || isNumbery(value) || value.toLowerCase() !== NORMAL_KEYWORD && keywordSets.fontWeightKeywords.has(value.toLowerCase())) {
checkWeight(value, decl)
return
}
}
}
function checkWeight(weightValue, decl) {
if (!isStandardSyntaxValue(weightValue)) {
return
}
if (isVariable(weightValue)) {
return
}
if (weightValue.toLowerCase() === INHERIT_KEYWORD || weightValue.toLowerCase() === INITIAL_KEYWORD) {
return
}
if (optionsMatches(options, "ignore", "relative") && keywordSets.fontWeightRelativeKeywords.has(weightValue.toLowerCase())) {
return
}
const weightValueOffset = decl.value.indexOf(weightValue)
if (expectation === "numeric") {
if (!isNumbery(weightValue)) {
return complain(messages.expected("numeric"))
}
}
if (expectation === "named-where-possible") {
if (isNumbery(weightValue)) {
if (_.includes(WEIGHTS_WITH_KEYWORD_EQUIVALENTS, weightValue)) {
complain(messages.expected("named"))
}
return
}
if (!keywordSets.fontWeightKeywords.has(weightValue.toLowerCase()) && weightValue.toLowerCase() !== NORMAL_KEYWORD) {
return complain(messages.invalidNamed(weightValue))
}
return
}
function complain(message) {
report({
ruleName,
result,
message,
node: decl,
index: declarationValueIndex(decl) + weightValueOffset,
})
}
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 51.61% | (16 / 31) | 0% | (0 / 8) | 0% | (0 / 2) | 51.61% | (16 / 31) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const declarationValueIndex = require("../../utils/declarationValueIndex")
const isStandardSyntaxFunction = require("../../utils/isStandardSyntaxFunction")
const matchesStringOrRegExp = require("../../utils/matchesStringOrRegExp")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const valueParser = require("postcss-value-parser")
const postcss = require("postcss")
const ruleName = "function-blacklist"
const messages = ruleMessages(ruleName, {
rejected: name => `Unexpected function "${name}"`,
})
const rule = function (blacklist) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: blacklist,
possible: [_.isString],
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const value = decl.value
valueParser(value).walk(function (node) {
if (node.type !== "function") {
return
}
if (!isStandardSyntaxFunction(node)) {
return
}
if (!matchesStringOrRegExp(postcss.vendor.unprefixed(node.value).toLowerCase(), blacklist)) {
return
}
report({
message: messages.rejected(node.value),
node: decl,
index: declarationValueIndex(decl) + node.sourceIndex,
result,
ruleName,
})
})
})
}
}
rule.primaryOptionArray = true
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 26.98% | (17 / 63) | 0% | (0 / 34) | 0% | (0 / 5) | 27.42% | (17 / 62) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isWhitespace = require("../../utils/isWhitespace")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const balancedMatch = require("balanced-match")
const styleSearch = require("style-search")
const valueParser = require("postcss-value-parser")
const ruleName = "function-calc-no-unspaced-operator"
const messages = ruleMessages(ruleName, {
expectedBefore: operator => `Expected single space before "${operator}" operator`,
expectedAfter: operator => `Expected single space after "${operator}" operator`,
expectedOperatorBeforeSign: operator => `Expected an operator before sign "${operator}"`,
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
function complain(message, node, index) {
report({ message, node, index, result, ruleName })
}
root.walkDecls(decl => {
valueParser(decl.value).walk(node => {
if (node.type !== "function" || node.value.toLowerCase() !== "calc") {
return
}
const parensMatch = balancedMatch("(", ")", valueParser.stringify(node))
const rawExpression = parensMatch.body
const expressionIndex = decl.source.start.column + decl.prop.length + (decl.raws.between || "").length + node.sourceIndex
const expression = blurVariables(rawExpression)
checkSymbol("+")
checkSymbol("-")
checkSymbol("*")
checkSymbol("/")
function checkSymbol(symbol) {
const styleSearchOptions = {
source: expression,
target: symbol,
functionArguments: "skip",
}
styleSearch(styleSearchOptions, match => {
const index = match.startIndex
// Deal with signs.
// (@ and $ are considered "digits" here to allow for variable syntaxes
// that permit signs in front of variables, e.g. `-$number`)
// As is "." to deal with fractional numbers without a leading zero
if ((symbol === "+" || symbol === "-") && /[\d@\$.]/.test(expression[index + 1])) {
const expressionBeforeSign = expression.substr(0, index)
// Ignore signs that directly follow a opening bracket
if (expressionBeforeSign[expressionBeforeSign.length - 1] === "(") {
return
}
// Ignore signs at the beginning of the expression
if (/^\s*$/.test(expressionBeforeSign)) {
return
}
// Otherwise, ensure that there is a real operator preceeding them
if (/[\*/+-]\s*$/.test(expressionBeforeSign)) {
return
}
// And if not, complain
complain(messages.expectedOperatorBeforeSign(symbol), decl, expressionIndex + index)
return
}
const beforeOk = expression[index - 1] === " " && !isWhitespace(expression[index - 2]) || newlineBefore(expression, index - 1)
if (!beforeOk) {
complain(messages.expectedBefore(symbol), decl, expressionIndex + index)
}
const afterOk = expression[index + 1] === " " && !isWhitespace(expression[index + 2]) || expression[index + 1] === "\n" || expression.substr(index + 1, 2) === "\r\n"
if (!afterOk) {
complain(messages.expectedAfter(symbol), decl, expressionIndex + index)
}
})
}
})
})
}
}
function blurVariables(source) {
return source.replace(/[\$@][^\)\s]+|#{.+?}/g, "0")
}
function newlineBefore(str, startIndex) {
let index = startIndex
while (index && isWhitespace(str[index])) {
if (str[index] === "\n") return true
index--
}
return false
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 52.63% | (10 / 19) | 0% | (0 / 2) | 0% | (0 / 1) | 52.63% | (10 / 19) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const functionCommaSpaceChecker = require("../functionCommaSpaceChecker")
const ruleName = "function-comma-newline-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected newline after \",\"",
expectedAfterMultiLine: () => "Expected newline after \",\" in a multi-line function",
rejectedAfterMultiLine: () => "Unexpected whitespace after \",\" in a multi-line function",
})
const rule = function (expectation) {
const checker = whitespaceChecker("newline", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"always-multi-line",
"never-multi-line",
],
})
if (!validOptions) {
return
}
functionCommaSpaceChecker({
root,
result,
locationChecker: checker.afterOneOnly,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 52.63% | (10 / 19) | 0% | (0 / 2) | 0% | (0 / 1) | 52.63% | (10 / 19) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const functionCommaSpaceChecker = require("../functionCommaSpaceChecker")
const ruleName = "function-comma-newline-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected newline before \",\"",
expectedBeforeMultiLine: () => "Expected newline before \",\" in a multi-line function",
rejectedBeforeMultiLine: () => "Unexpected whitespace before \",\" in a multi-line function",
})
const rule = function (expectation) {
const checker = whitespaceChecker("newline", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"always-multi-line",
"never-multi-line",
],
})
if (!validOptions) {
return
}
functionCommaSpaceChecker({
root,
result,
locationChecker: checker.beforeAllowingIndentation,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 50% | (10 / 20) | 0% | (0 / 2) | 0% | (0 / 1) | 50% | (10 / 20) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const functionCommaSpaceChecker = require("../functionCommaSpaceChecker")
const ruleName = "function-comma-space-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected single space after \",\"",
rejectedAfter: () => "Unexpected whitespace after \",\"",
expectedAfterSingleLine: () => "Expected single space after \",\" in a single-line function",
rejectedAfterSingleLine: () => "Unexpected whitespace after \",\" in a single-line function",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-single-line",
"never-single-line",
],
})
if (!validOptions) {
return
}
functionCommaSpaceChecker({
root,
result,
locationChecker: checker.after,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 50% | (10 / 20) | 0% | (0 / 2) | 0% | (0 / 1) | 50% | (10 / 20) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const functionCommaSpaceChecker = require("../functionCommaSpaceChecker")
const ruleName = "function-comma-space-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected single space before \",\"",
rejectedBefore: () => "Unexpected whitespace before \",\"",
expectedBeforeSingleLine: () => "Expected single space before \",\" in a single-line function",
rejectedBeforeSingleLine: () => "Unexpected whitespace before \",\" in a single-line function",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-single-line",
"never-single-line",
],
})
if (!validOptions) {
return
}
functionCommaSpaceChecker({
root,
result,
locationChecker: checker.before,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 31.71% | (13 / 41) | 0% | (0 / 20) | 0% | (0 / 3) | 31.71% | (13 / 41) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const functionArgumentsSearch = require("../../utils/functionArgumentsSearch")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const postcss = require("postcss")
const ruleName = "function-linear-gradient-no-nonstandard-direction"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected nonstandard direction",
})
function isStandardDirection(source, withToPrefix) {
const regexp = withToPrefix ? /^to (top|left|bottom|right)(?: (top|left|bottom|right))?$/ : /^(top|left|bottom|right)(?: (top|left|bottom|right))?$/
const matches = source.match(regexp)
if (!matches) {
return false
}
if (matches.length === 2) {
return true
}
// Cannot repeat side-or-corner, e.g. "to top top"
if (matches.length === 3 && matches[1] !== matches[2]) {
return true
}
return false
}
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkDecls(decl => {
functionArgumentsSearch(decl.toString().toLowerCase(), "linear-gradient", (expression, expressionIndex) => {
const firstArg = expression.split(",")[0].trim()
// If the first character is a number, we can assume the user intends an angle
if (/[\d\.]/.test(firstArg[0])) {
if (/^[\d\.]+(?:deg|grad|rad|turn)$/.test(firstArg)) {
return
}
complain()
return
}
// The first argument may not be a direction: it may be an angle,
// or a color stop (in which case user gets default direction, "to bottom")
// cf. https://drafts.csswg.org/css-images-3/#linear-gradient-syntax
if (!/left|right|top|bottom/.test(firstArg)) {
return
}
const withToPrefix = !postcss.vendor.prefix(decl.value)
if (!isStandardDirection(firstArg, withToPrefix)) {
complain()
return
}
function complain() {
report({
message: messages.rejected,
node: decl,
index: expressionIndex,
result,
ruleName,
})
}
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 37.93% | (11 / 29) | 0% | (0 / 10) | 0% | (0 / 1) | 37.93% | (11 / 29) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const styleSearch = require("style-search")
const ruleName = "function-max-empty-lines"
const messages = ruleMessages(ruleName, {
expected: max => `Expected no more than ${max} empty line(s)`,
})
const rule = function (max) {
const maxAdjacentNewlines = max + 1
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: max,
possible: _.isNumber,
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
if (decl.value.indexOf("(") === -1) {
return
}
const declString = decl.toString()
const repeatLFNewLines = _.repeat("\n", maxAdjacentNewlines)
const repeatCRLFNewLines = _.repeat("\r\n", maxAdjacentNewlines)
styleSearch({
source: declString,
target: "\n",
functionArguments: "only",
}, match => {
if (declString.substr(match.startIndex + 1, maxAdjacentNewlines) === repeatLFNewLines || declString.substr(match.startIndex + 1, maxAdjacentNewlines * 2) === repeatCRLFNewLines) {
// Put index at `\r` if it's CRLF, otherwise leave it at `\n`
let index = match.startIndex
if (declString[index - 1] === "\r") {
index -= 1
}
report({
message: messages.expected(max),
node: decl,
index,
result,
ruleName,
})
}
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 42.86% | (18 / 42) | 0% | (0 / 21) | 0% | (0 / 2) | 42.86% | (18 / 42) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1 1 1 1 | "use strict"
const declarationValueIndex = require("../../utils/declarationValueIndex")
const isStandardSyntaxFunction = require("../../utils/isStandardSyntaxFunction")
const matchesStringOrRegExp = require("../../utils/matchesStringOrRegExp")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const keywordSets = require("../../reference/keywordSets")
const _ = require("lodash")
const valueParser = require("postcss-value-parser")
const ruleName = "function-name-case"
const messages = ruleMessages(ruleName, {
expected: (actual, expected) => `Expected "${actual}" to be "${expected}"`,
})
const mapLowercaseFunctionNamesToCamelCase = new Map()
keywordSets.camelCaseFunctionNames.forEach(func => {
mapLowercaseFunctionNamesToCamelCase.set(func.toLowerCase(), func)
})
const rule = function (expectation, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"lower",
"upper",
],
}, {
actual: options,
possible: {
ignoreFunctions: [_.isString],
},
optional: true,
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const value = decl.value
valueParser(value).walk(function (node) {
if (node.type !== "function" || !isStandardSyntaxFunction(node)) {
return
}
const functionName = node.value
const functionNameLowerCase = functionName.toLowerCase()
const ignoreFunctions = options && options.ignoreFunctions || []
if (ignoreFunctions.length > 0 && matchesStringOrRegExp(functionName, ignoreFunctions)) {
return
}
let expectedFunctionName = null
if (expectation === "lower" && mapLowercaseFunctionNamesToCamelCase.has(functionNameLowerCase)) {
expectedFunctionName = mapLowercaseFunctionNamesToCamelCase.get(functionNameLowerCase)
} else if (expectation === "lower") {
expectedFunctionName = functionNameLowerCase
} else {
expectedFunctionName = functionName.toUpperCase()
}
if (functionName === expectedFunctionName) {
return
}
report({
message: messages.expected(functionName, expectedFunctionName),
node: decl,
index: declarationValueIndex(decl) + node.sourceIndex,
result,
ruleName,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 33.33% | (15 / 45) | 0% | (0 / 36) | 0% | (0 / 3) | 33.33% | (15 / 45) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const declarationValueIndex = require("../../utils/declarationValueIndex")
const isSingleLineString = require("../../utils/isSingleLineString")
const isStandardSyntaxFunction = require("../../utils/isStandardSyntaxFunction")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const valueParser = require("postcss-value-parser")
const ruleName = "function-parentheses-newline-inside"
const messages = ruleMessages(ruleName, {
expectedOpening: "Expected newline after \"(\"",
expectedClosing: "Expected newline before \")\"",
expectedOpeningMultiLine: "Expected newline after \"(\" in a multi-line function",
rejectedOpeningMultiLine: "Unexpected whitespace after \"(\" in a multi-line function",
expectedClosingMultiLine: "Expected newline before \")\" in a multi-line function",
rejectedClosingMultiLine: "Unexpected whitespace before \")\" in a multi-line function",
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"always-multi-line",
"never-multi-line",
],
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
if (decl.value.indexOf("(") === -1) {
return
}
valueParser(decl.value).walk(valueNode => {
if (valueNode.type !== "function") {
return
}
if (!isStandardSyntaxFunction(valueNode)) {
return
}
const functionString = valueParser.stringify(valueNode)
const isMultiLine = !isSingleLineString(functionString)
function containsNewline(str) {
return str.indexOf("\n") !== -1
}
// Check opening ...
const openingIndex = valueNode.sourceIndex + valueNode.value.length + 1
if (expectation === "always" && !containsNewline(valueNode.before)) {
complain(messages.expectedOpening, openingIndex)
}
if (isMultiLine && expectation === "always-multi-line" && !containsNewline(valueNode.before)) {
complain(messages.expectedOpeningMultiLine, openingIndex)
}
if (isMultiLine && expectation === "never-multi-line" && valueNode.before !== "") {
complain(messages.rejectedOpeningMultiLine, openingIndex)
}
// Check closing ...
const closingIndex = valueNode.sourceIndex + functionString.length - 2
if (expectation === "always" && !containsNewline(valueNode.after)) {
complain(messages.expectedClosing, closingIndex)
}
if (isMultiLine && expectation === "always-multi-line" && !containsNewline(valueNode.after)) {
complain(messages.expectedClosingMultiLine, closingIndex)
}
if (isMultiLine && expectation === "never-multi-line" && valueNode.after !== "") {
complain(messages.rejectedClosingMultiLine, closingIndex)
}
})
function complain(message, offset) {
report({
ruleName,
result,
message,
node: decl,
index: declarationValueIndex(decl) + offset,
})
}
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 29.79% | (14 / 47) | 0% | (0 / 44) | 0% | (0 / 2) | 29.79% | (14 / 47) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const declarationValueIndex = require("../../utils/declarationValueIndex")
const isSingleLineString = require("../../utils/isSingleLineString")
const isStandardSyntaxFunction = require("../../utils/isStandardSyntaxFunction")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const valueParser = require("postcss-value-parser")
const ruleName = "function-parentheses-space-inside"
const messages = ruleMessages(ruleName, {
expectedOpening: "Expected single space after \"(\"",
rejectedOpening: "Unexpected whitespace after \"(\"",
expectedClosing: "Expected single space before \")\"",
rejectedClosing: "Unexpected whitespace before \")\"",
expectedOpeningSingleLine: "Expected single space after \"(\" in a single-line function",
rejectedOpeningSingleLine: "Unexpected whitespace after \"(\" in a single-line function",
expectedClosingSingleLine: "Expected single space before \")\" in a single-line function",
rejectedClosingSingleLine: "Unexpected whitespace before \")\" in a single-line function",
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-single-line",
"never-single-line",
],
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
if (decl.value.indexOf("(") === -1) {
return
}
valueParser(decl.value).walk(valueNode => {
if (valueNode.type !== "function") {
return
}
if (!isStandardSyntaxFunction(valueNode)) {
return
}
const functionString = valueParser.stringify(valueNode)
const isSingleLine = isSingleLineString(functionString)
// Check opening ...
const openingIndex = valueNode.sourceIndex + valueNode.value.length + 1
if (expectation === "always" && valueNode.before !== " ") {
complain(messages.expectedOpening, openingIndex)
}
if (expectation === "never" && valueNode.before !== "") {
complain(messages.rejectedOpening, openingIndex)
}
if (isSingleLine && expectation === "always-single-line" && valueNode.before !== " ") {
complain(messages.expectedOpeningSingleLine, openingIndex)
}
if (isSingleLine && expectation === "never-single-line" && valueNode.before !== "") {
complain(messages.rejectedOpeningSingleLine, openingIndex)
}
// Check closing ...
const closingIndex = valueNode.sourceIndex + functionString.length - 2
if (expectation === "always" && valueNode.after !== " ") {
complain(messages.expectedClosing, closingIndex)
}
if (expectation === "never" && valueNode.after !== "") {
complain(messages.rejectedClosing, closingIndex)
}
if (isSingleLine && expectation === "always-single-line" && valueNode.after !== " ") {
complain(messages.expectedClosingSingleLine, closingIndex)
}
if (isSingleLine && expectation === "never-single-line" && valueNode.after !== "") {
complain(messages.rejectedClosingSingleLine, closingIndex)
}
})
function complain(message, offset) {
report({
ruleName,
result,
message,
node: decl,
index: declarationValueIndex(decl) + offset,
})
}
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 41.38% | (12 / 29) | 0% | (0 / 20) | 0% | (0 / 2) | 41.38% | (12 / 29) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxValue = require("../../utils/isStandardSyntaxValue")
const isVariable = require("../../utils/isVariable")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const valueParser = require("postcss-value-parser")
const ruleName = "function-url-data-uris"
const messages = ruleMessages(ruleName, {
expected: "Expected a data URI",
rejected: "Unexpected data URI",
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
root.walkDecls(function (decl) {
valueParser(decl.value).walk(valueNode => {
if (valueNode.type !== "function" || valueNode.value.toLowerCase() !== "url" || !valueNode.nodes.length > 0) {
return
}
const urlValueNode = valueNode.nodes[0]
if (!urlValueNode.value || !isStandardSyntaxValue(urlValueNode.value) || isVariable(urlValueNode.value)) {
return
}
const valueContainDataUris = urlValueNode.value.toLowerCase().indexOf("data:") === 0
const needUrlDataUris = expectation === "always"
if (valueContainDataUris && needUrlDataUris || !valueContainDataUris && !needUrlDataUris) {
return
}
const message = needUrlDataUris ? messages.expected : messages.rejected
report({
message,
node: decl,
result,
ruleName,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 54.55% | (12 / 22) | 0% | (0 / 6) | 0% | (0 / 2) | 54.55% | (12 / 22) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const functionArgumentsSearch = require("../../utils/functionArgumentsSearch")
const isStandardSyntaxUrl = require("../../utils/isStandardSyntaxUrl")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const ruleName = "function-url-no-scheme-relative"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected scheme-relative url",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkDecls(function (decl) {
functionArgumentsSearch(decl.toString().toLowerCase(), "url", (args, index) => {
const url = _.trim(args, " '\"")
if (!isStandardSyntaxUrl(url) || url.indexOf("//") !== 0) {
return
}
report({
message: messages.rejected,
node: decl,
index,
result,
ruleName,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 32.14% | (18 / 56) | 0% | (0 / 18) | 0% | (0 / 6) | 32.14% | (18 / 56) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../../utils/atRuleParamIndex")
const functionArgumentsSearch = require("../../utils/functionArgumentsSearch")
const isStandardSyntaxUrl = require("../../utils/isStandardSyntaxUrl")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const ruleName = "function-url-quotes"
const messages = ruleMessages(ruleName, {
expected: () => "Expected quotes",
rejected: () => "Unexpected quotes",
})
const rule = function (expectation, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
}, {
actual: options,
possible: {
except: ["empty"],
},
optional: true,
})
if (!validOptions) {
return
}
root.walkAtRules(checkStatement)
root.walkRules(checkStatement)
function checkStatement(statement) {
if (statement.type === "atrule") {
checkAtRuleParams(statement)
}
statement.walkDecls(function (decl) {
functionArgumentsSearch(decl.toString().toLowerCase(), "url", (args, index) => {
checkArgs(args, decl, index, "url")
})
})
}
function checkAtRuleParams(atRule) {
const atRuleParamsLowerCase = atRule.params.toLowerCase()
functionArgumentsSearch(atRuleParamsLowerCase, "url", (args, index) => {
checkArgs(args, atRule, index + atRuleParamIndex(atRule), "url")
})
functionArgumentsSearch(atRuleParamsLowerCase, "url-prefix", (args, index) => {
checkArgs(args, atRule, index + atRuleParamIndex(atRule), "url-prefix")
})
functionArgumentsSearch(atRuleParamsLowerCase, "domain", (args, index) => {
checkArgs(args, atRule, index + atRuleParamIndex(atRule), "domain")
})
}
function checkArgs(args, node, index, functionName) {
let shouldHasQuotes = expectation === "always"
const leftTrimmedArgs = args.trimLeft()
if (!isStandardSyntaxUrl(leftTrimmedArgs)) {
return
}
const complaintIndex = index + args.length - leftTrimmedArgs.length
const hasQuotes = leftTrimmedArgs[0] === "'" || leftTrimmedArgs[0] === "\""
const trimmedArg = args.trim()
const isEmptyArgument = _.includes([
"",
"''",
"\"\"",
], trimmedArg)
if (optionsMatches(options, "except", "empty") && isEmptyArgument) {
shouldHasQuotes = !shouldHasQuotes
}
if (shouldHasQuotes) {
if (hasQuotes) {
return
}
complain(messages.expected(functionName), node, complaintIndex)
} else {
if (!hasQuotes) {
return
}
complain(messages.rejected(functionName), node, complaintIndex)
}
}
function complain(message, node, index) {
report({
message,
node,
index,
result,
ruleName,
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 38.46% | (15 / 39) | 0% | (0 / 14) | 0% | (0 / 2) | 38.46% | (15 / 39) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const containsString = require("../../utils/containsString")
const functionArgumentsSearch = require("../../utils/functionArgumentsSearch")
const isStandardSyntaxUrl = require("../../utils/isStandardSyntaxUrl")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const parse = require("url").parse
const ruleName = "function-url-scheme-whitelist"
const messages = ruleMessages(ruleName, {
rejected: scheme => `Unexpected url scheme "${scheme}:"`,
})
const rule = function (whitelist) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: whitelist,
possible: [_.isString],
})
if (!validOptions) {
return
}
root.walkDecls(function (decl) {
functionArgumentsSearch(decl.toString().toLowerCase(), "url", (args, index) => {
const unspacedUrlString = _.trim(args, " ")
if (!isStandardSyntaxUrl(unspacedUrlString)) {
return
}
const urlString = _.trim(unspacedUrlString, "'\"")
const url = parse(urlString)
if (url.protocol === null) {
return
}
const scheme = url.protocol.toLowerCase().slice(0, -1) // strip trailing `:`
// The URL spec does not require a scheme to be followed by `//`, but checking
// for it allows this rule to differentiate <scheme>:<hostname> urls from
// <hostname>:<port> urls. `data:` scheme urls are an exception to this rule.
const slashIndex = url.protocol.length
const expectedSlashes = urlString.slice(slashIndex, slashIndex + 2)
const isSchemeLessUrl = expectedSlashes !== "//" && scheme !== "data"
if (isSchemeLessUrl) {
return
}
const whitelistLowerCase = typeof whitelist === "string" ? whitelist.toLowerCase() : whitelist.join("|").toLowerCase().split("|")
if (containsString(scheme, whitelistLowerCase)) {
return
}
report({
message: messages.rejected(scheme),
node: decl,
index,
result,
ruleName,
})
})
})
}
}
rule.primaryOptionArray = true
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 50% | (16 / 32) | 0% | (0 / 8) | 0% | (0 / 2) | 50% | (16 / 32) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const declarationValueIndex = require("../../utils/declarationValueIndex")
const isStandardSyntaxFunction = require("../../utils/isStandardSyntaxFunction")
const matchesStringOrRegExp = require("../../utils/matchesStringOrRegExp")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const valueParser = require("postcss-value-parser")
const postcss = require("postcss")
const ruleName = "function-whitelist"
const messages = ruleMessages(ruleName, {
rejected: name => `Unexpected function "${name}"`,
})
const rule = function (whitelistInput) {
const whitelist = [].concat(whitelistInput)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: whitelist,
possible: [_.isString],
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const value = decl.value
valueParser(value).walk(function (node) {
if (node.type !== "function") {
return
}
if (!isStandardSyntaxFunction(node)) {
return
}
if (matchesStringOrRegExp(postcss.vendor.unprefixed(node.value).toLowerCase(), whitelist)) {
return
}
report({
message: messages.rejected(node.value),
node: decl,
index: declarationValueIndex(decl) + node.sourceIndex,
result,
ruleName,
})
})
})
}
}
rule.primaryOptionArray = true
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 37.14% | (13 / 35) | 0% | (0 / 16) | 0% | (0 / 2) | 37.14% | (13 / 35) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isWhitespace = require("../../utils/isWhitespace")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const styleSearch = require("style-search")
const ruleName = "function-whitespace-after"
const messages = ruleMessages(ruleName, {
expected: "Expected whitespace after \")\"",
rejected: "Unexpected whitespace after \")\"",
})
const ACCEPTABLE_AFTER_CLOSING_PAREN = new Set([
")",
",",
"}",
":",
undefined,
])
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const declString = decl.toString()
styleSearch({
source: declString,
target: ")",
functionArguments: "only",
}, match => {
checkClosingParen(declString, match.startIndex, decl)
})
})
function checkClosingParen(source, index, node) {
const nextChar = source[index + 1]
if (expectation === "always") {
// Allow for the next character to be a single empty space,
// another closing parenthesis, a comma, or the end of the value
if (nextChar === " ") {
return
}
if (nextChar === "\n") {
return
}
if (source.substr(index + 1, 2) === "\r\n") {
return
}
if (ACCEPTABLE_AFTER_CLOSING_PAREN.has(nextChar)) {
return
}
report({
message: messages.expected,
node,
index: index + 1,
result,
ruleName,
})
} else if (expectation === "never") {
if (isWhitespace(nextChar)) {
report({
message: messages.rejected,
node,
index: index + 1,
result,
ruleName,
})
}
}
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 17.86% | (20 / 112) | 0% | (0 / 112) | 0% | (0 / 7) | 18.02% | (20 / 111) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const beforeBlockString = require("../../utils/beforeBlockString")
const hasBlock = require("../../utils/hasBlock")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const styleSearch = require("style-search")
const ruleName = "indentation"
const messages = ruleMessages(ruleName, {
expected: x => `Expected indentation of ${x}`,
})
/**
* @param {number|"tab"} space - Number of whitespaces to expect, or else
* keyword "tab" for single `\t`
* @param {object} [options]
*/
const rule = function (space) {
const options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}
const isTab = space === "tab"
const indentChar = isTab ? "\t" : _.repeat(" ", space)
const warningWord = isTab ? "tab" : "space"
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: space,
possible: [
_.isNumber,
"tab",
],
}, {
actual: options,
possible: {
except: [
"block",
"value",
"param",
],
ignore: [
"value",
"param",
"inside-parens",
],
indentInsideParens: [
"twice",
"once-at-root-twice-in-block",
],
indentClosingBrace: [_.isBoolean],
},
optional: true,
})
if (!validOptions) {
return
}
// Cycle through all nodes using walk.
root.walk(node => {
const nodeLevel = indentationLevel(node)
const expectedWhitespace = _.repeat(indentChar, nodeLevel)
let before = (node.raws.before || "")
const after = (node.raws.after || "")
// Only inspect the spaces before the node
// if this is the first node in root
// or there is a newline in the `before` string.
// (If there is no newline before a node,
// there is no "indentation" to check.)
const inspectBefore = root.first === node || before.indexOf("\n") !== -1
// Cut out any * hacks from `before`
before = before[before.length - 1] === "*" || before[before.length - 1] === "_" ? before.slice(0, before.length - 1) : before
// Inspect whitespace in the `before` string that is
// *after* the *last* newline character,
// because anything besides that is not indentation for this node:
// it is some other kind of separation, checked by some separate rule
if (inspectBefore && before.slice(before.lastIndexOf("\n") + 1) !== expectedWhitespace) {
report({
message: messages.expected(legibleExpectation(nodeLevel)),
node,
result,
ruleName,
})
}
// Only blocks have the `after` string to check.
// Only inspect `after` strings that start with a newline;
// otherwise there's no indentation involved.
// And check `indentClosingBrace` to see if it should be indented an extra level.
const closingBraceLevel = options.indentClosingBrace ? nodeLevel + 1 : nodeLevel
if (hasBlock(node) && after && after.indexOf("\n") !== -1 && after.slice(after.lastIndexOf("\n") + 1) !== _.repeat(indentChar, closingBraceLevel)) {
report({
message: messages.expected(legibleExpectation(closingBraceLevel)),
node,
index: node.toString().length - 1,
result,
ruleName,
})
}
// If this is a declaration, check the value
if (node.value) {
checkValue(node, nodeLevel)
}
// If this is a rule, check the selector
if (node.selector) {
checkSelector(node, nodeLevel)
}
// If this is an at rule, check the params
if (node.type === "atrule") {
checkAtRuleParams(node, nodeLevel)
}
})
function indentationLevel(node) {
const level = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0
if (node.parent.type === "root") {
return level
}
let calculatedLevel
// Indentation level equals the ancestor nodes
// separating this node from root; so recursively
// run this operation
calculatedLevel = indentationLevel(node.parent, level + 1)
// If options.except includes "block",
// blocks are taken down one from their calculated level
// (all blocks are the same level as their parents)
if (optionsMatches(options, "except", "block") && (node.type === "rule" || node.type === "atrule") && hasBlock(node)) {
calculatedLevel--
}
return calculatedLevel
}
function checkValue(decl, declLevel) {
if (decl.value.indexOf("\n") === -1) {
return
}
if (optionsMatches(options, "ignore", "value")) {
return
}
const declString = decl.toString()
const valueLevel = optionsMatches(options, "except", "value") ? declLevel : declLevel + 1
checkMultilineBit(declString, valueLevel, decl)
}
function checkSelector(rule, ruleLevel) {
const selector = rule.selector
// Less mixins have params, and they should be indented extra
if (rule.params) {
ruleLevel += 1
}
checkMultilineBit(selector, ruleLevel, rule)
}
function checkAtRuleParams(atRule, ruleLevel) {
if (optionsMatches(options, "ignore", "param")) {
return
}
// @nest rules should be treated like regular rules, not expected
// to have their params (selectors) indented
const paramLevel = optionsMatches(options, "except", "param") || atRule.name === "nest" ? ruleLevel : ruleLevel + 1
checkMultilineBit(beforeBlockString(atRule).trim(), paramLevel, atRule)
}
function checkMultilineBit(source, newlineIndentLevel, node) {
if (source.indexOf("\n") === -1) {
return
}
// `outsideParens` because function arguments and also non-standard parenthesized stuff like
// Sass maps are ignored to allow for arbitrary indentation
let parentheticalDepth = 0
styleSearch({
source,
target: "\n",
outsideParens: optionsMatches(options, "ignore", "inside-parens"),
}, (match, matchCount) => {
const precedesClosingParenthesis = /^[ \t]*\)/.test(source.slice(match.startIndex + 1))
if (optionsMatches(options, "ignore", "inside-parens") && (precedesClosingParenthesis || match.insideParens)) {
return
}
let expectedIndentLevel = newlineIndentLevel
// Modififications for parenthetical content
if (!optionsMatches(options, "ignore", "inside-parens") && match.insideParens) {
// If the first match in is within parentheses, reduce the parenthesis penalty
if (matchCount === 1) parentheticalDepth -= 1
// Account for windows line endings
let newlineIndex = match.startIndex
if (source[match.startIndex - 1] === "\r") {
newlineIndex--
}
const followsOpeningParenthesis = /\([ \t]*$/.test(source.slice(0, newlineIndex))
if (followsOpeningParenthesis) {
parentheticalDepth += 1
}
expectedIndentLevel += parentheticalDepth
if (precedesClosingParenthesis) {
parentheticalDepth -= 1
}
switch (options.indentInsideParens) {
case "twice":
if (!precedesClosingParenthesis || options.indentClosingBrace) {
expectedIndentLevel += 1
}
break
case "once-at-root-twice-in-block":
if (node.parent === root) {
if (precedesClosingParenthesis && !options.indentClosingBrace) {
expectedIndentLevel -= 1
}
break
}
if (!precedesClosingParenthesis || options.indentClosingBrace) {
expectedIndentLevel += 1
}
break
default:
if (precedesClosingParenthesis && !options.indentClosingBrace) {
expectedIndentLevel -= 1
}
}
}
// Starting at the index after the newline, we want to
// check that the whitespace characters (excluding newlines) before the first
// non-whitespace character equal the expected indentation
const afterNewlineSpaceMatches = /^([ \t]*)\S/.exec(source.slice(match.startIndex + 1))
if (!afterNewlineSpaceMatches) {
return
}
const afterNewlineSpace = afterNewlineSpaceMatches[1]
if (afterNewlineSpace !== _.repeat(indentChar, expectedIndentLevel)) {
report({
message: messages.expected(legibleExpectation(expectedIndentLevel)),
node,
index: match.startIndex + afterNewlineSpace.length + 1,
result,
ruleName,
})
}
})
}
}
function legibleExpectation(level) {
const count = isTab ? level : level * space
const quantifiedWarningWord = count === 1 ? warningWord : warningWord + "s"
return `${count} ${quantifiedWarningWord}`
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 50% | (9 / 18) | 0% | (0 / 4) | 0% | (0 / 1) | 50% | (9 / 18) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 1 1 1 1 1 1 1 1 1 | "use strict"
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "keyframe-declaration-no-important"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected !important",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkAtRules(/^(-(moz|webkit)-)?keyframes$/i, atRuleKeyframes => {
atRuleKeyframes.walkDecls(decl => {
if (!decl.important) {
return
}
report({
message: messages.rejected,
node: decl,
word: "important",
result,
ruleName,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 35.42% | (17 / 48) | 0% | (0 / 21) | 0% | (0 / 2) | 36.17% | (17 / 47) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const beforeBlockString = require("../../utils/beforeBlockString")
const blurComments = require("../../utils/blurComments")
const hasBlock = require("../../utils/hasBlock")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const keywordSets = require("../../reference/keywordSets")
const styleSearch = require("style-search")
const valueParser = require("postcss-value-parser")
const ruleName = "length-zero-no-unit"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected unit",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkDecls(decl => {
check(blurComments(decl.toString()), decl)
})
root.walkAtRules(atRule => {
const source = hasBlock(atRule) ? beforeBlockString(atRule, { noRawBefore: true }) : atRule.toString()
check(source, atRule)
})
function check(value, node) {
const ignorableIndexes = new Set()
styleSearch({ source: value, target: "0" }, match => {
const index = match.startIndex
// Given a 0 somewhere in the full property value (not in a string, thanks
// to styleSearch) we need to isolate the value that contains the zero.
// To do so, we'll find the last index before the 0 of a character that would
// divide one value in a list from another, and the next index of such a
// character; then we build a substring from those indexes, which we can
// assess.
// If a single value includes multiple 0's (e.g. 100.01px), we don't want
// each 0 to be treated as a separate value, possibly resulting in multiple
// warnings for the same value (e.g. 0.00px).
//
// This check prevents that from happening: we build and check against a
// Set containing all the indexes that are part of a value already validated.
if (ignorableIndexes.has(index)) {
return
}
const prevValueBreakIndex = _.findLastIndex(value.substr(0, index), char => {
return [
" ",
",",
")",
"(",
"#",
].indexOf(char) !== -1
})
// Ignore hex colors
if (value[prevValueBreakIndex] === "#") {
return
}
// If no prev break was found, this value starts at 0
const valueWithZeroStart = prevValueBreakIndex === -1 ? 0 : prevValueBreakIndex + 1
const nextValueBreakIndex = _.findIndex(value.substr(valueWithZeroStart), char => {
return [
" ",
",",
")",
].indexOf(char) !== -1
})
// If no next break was found, this value ends at the end of the string
const valueWithZeroEnd = nextValueBreakIndex === -1 ? value.length : nextValueBreakIndex + valueWithZeroStart
const valueWithZero = value.slice(valueWithZeroStart, valueWithZeroEnd)
const parsedValue = valueParser.unit(valueWithZero)
if (!parsedValue || parsedValue && !parsedValue.unit) {
return
}
// Add the indexes to ignorableIndexes so the same value will not
// be checked multiple times.
_.range(valueWithZeroStart, valueWithZeroEnd).forEach(i => ignorableIndexes.add(i))
// Only pay attention if the value parses to 0
// and units with lengths
if (parseFloat(valueWithZero, 10) !== 0 || !keywordSets.lengthUnits.has(parsedValue.unit.toLowerCase())) {
return
}
report({
message: messages.rejected,
node,
index: valueWithZeroEnd - parsedValue.unit.length,
result,
ruleName,
})
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 33.33% | (13 / 39) | 0% | (0 / 18) | 0% | (0 / 2) | 33.33% | (13 / 39) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const styleSearch = require("style-search")
const ruleName = "max-empty-lines"
const messages = ruleMessages(ruleName, {
expected: max => `Expected no more than ${max} empty line(s)`,
})
const rule = function (max, options) {
const maxAdjacentNewlines = max + 1
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: max,
possible: _.isNumber,
}, {
actual: options,
possible: {
ignore: [
"comments",
],
},
optional: true,
})
if (!validOptions) {
return
}
const rootString = root.toString()
const repeatLFNewLines = _.repeat("\n", maxAdjacentNewlines)
const repeatCRLFNewLines = _.repeat("\r\n", maxAdjacentNewlines)
const ignoreComments = optionsMatches(options, "ignore", "comments")
styleSearch({ source: rootString, target: "\n" }, match => {
checkMatch(rootString, match.endIndex, root)
})
// We must check comments separately in order to accommodate stupid
// `//`-comments from SCSS, which postcss-scss converts to `/* ... */`,
// which adds to extra characters at the end, which messes up our
// warning position
if (!ignoreComments) {
root.walkComments(comment => {
const source = (comment.raws.left || "") + comment.text + (comment.raws.right || "")
styleSearch({ source, target: "\n" }, match => {
checkMatch(source, match.endIndex, comment, 2)
})
})
}
function checkMatch(source, matchEndIndex, node) {
const offset = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0
let violationIndex = false
if (source.substr(matchEndIndex, maxAdjacentNewlines) === repeatLFNewLines) {
violationIndex = matchEndIndex + maxAdjacentNewlines
} else if (source.substr(matchEndIndex, maxAdjacentNewlines * 2) === repeatCRLFNewLines) {
violationIndex = matchEndIndex + maxAdjacentNewlines * 2
}
if (!violationIndex) {
return
}
report({
message: messages.expected(max),
node,
index: violationIndex + offset,
result,
ruleName,
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 25.42% | (15 / 59) | 0% | (0 / 28) | 0% | (0 / 3) | 25.42% | (15 / 59) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const execall = require("execall")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const styleSearch = require("style-search")
const ruleName = "max-line-length"
const messages = ruleMessages(ruleName, {
expected: l => `Expected line length to be no more than ${l} characters`,
})
const rule = function (maxLength, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: maxLength,
possible: _.isNumber,
}, {
actual: options,
possible: {
ignore: [
"non-comments",
"comments",
],
ignorePattern: [_.isString],
},
optional: true,
})
if (!validOptions) {
return
}
const rootString = root.source.input.css
const ignoreNonComments = optionsMatches(options, "ignore", "non-comments")
const ignoreComments = optionsMatches(options, "ignore", "comments")
// Check first line
checkNewline({ endIndex: 0 })
// Check subsequent lines
styleSearch({ source: rootString, target: ["\n"], comments: "check" }, checkNewline)
function complain(index) {
report({
index,
result,
ruleName,
message: messages.expected(maxLength),
node: root,
})
}
function checkNewline(match) {
let nextNewlineIndex = rootString.indexOf("\n", match.endIndex)
if (rootString[nextNewlineIndex - 1] === "\r") {
nextNewlineIndex -= 1
}
// Accommodate last line
if (nextNewlineIndex === -1) {
nextNewlineIndex = rootString.length
}
const rawLineLength = nextNewlineIndex - match.endIndex
const lineText = rootString.slice(match.endIndex, nextNewlineIndex)
if (optionsMatches(options, "ignorePattern", lineText)) {
return
}
const urlArgumentsLength = execall(/url\((.*)\)/ig, lineText).reduce((result, match) => {
return result + _.get(match, "sub[0].length", 0)
}, 0)
const importUrlsLength = execall(/\@import\s+(['"].*['"])/ig, lineText).reduce((result, match) => {
return result + _.get(match, "sub[0].length", 0)
}, 0)
// If the line's length is less than or equal to the specified
// max, ignore it ... So anything below is liable to be complained about.
// **Note that the length of any url arguments or import urls
// are excluded from the calculation.**
if (rawLineLength - urlArgumentsLength - importUrlsLength <= maxLength) {
return
}
const complaintIndex = nextNewlineIndex - 1
if (ignoreComments) {
if (match.insideComment) {
return
}
// This trimming business is to notice when the line starts a
// comment but that comment is indented, e.g.
// /* something here */
const nextTwoChars = rootString.slice(match.endIndex).trim().slice(0, 2)
if (nextTwoChars === "/*" || nextTwoChars === "//") {
return
}
}
if (ignoreNonComments) {
if (match.insideComment) {
return complain(complaintIndex)
}
// This trimming business is to notice when the line starts a
// comment but that comment is indented, e.g.
// /* something here */
const nextTwoChars = rootString.slice(match.endIndex).trim().slice(0, 2)
if (nextTwoChars !== "/*" && nextTwoChars !== "//") {
return
}
return complain(complaintIndex)
}
// If there are no spaces besides initial (indent) spaces, ignore it
const lineString = rootString.slice(match.endIndex, nextNewlineIndex)
if (lineString.replace(/^\s+/, "").indexOf(" ") === -1) {
return
}
return complain(complaintIndex)
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 34.15% | (14 / 41) | 0% | (0 / 26) | 0% | (0 / 3) | 35.9% | (14 / 39) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const hasBlock = require("../../utils/hasBlock")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const ruleName = "max-nesting-depth"
const messages = ruleMessages(ruleName, {
expected: depth => `Expected nesting depth to be no more than ${depth}`,
})
const rule = function (max, options) {
const ignoreAtRulesWithoutDeclarationBlocks = optionsMatches(options, "ignore", "at-rules-without-declaration-blocks") || optionsMatches(options, "ignore", "blockless-at-rules")
const isIgnoreAtRule = node => node.type === "atrule" && optionsMatches(options, "ignoreAtRules", node.name)
return (root, result) => {
validateOptions(result, ruleName, {
actual: max,
possible: [_.isNumber],
}, {
optional: true,
actual: options,
possible: {
ignore: [
"at-rules-without-declaration-blocks",
"blockless-at-rules",
],
ignoreAtRules: [_.isString],
},
})
if (optionsMatches(options, "ignore", "at-rules-without-declaration-blocks")) {
result.warn((
"'max-nesting-depth\'s' \"at-rules-without-declaration-blocks\" option has been deprecated and in 8.0 will be removed. Instead use the \"blockless-at-rules\" option."
), {
stylelintType: "deprecation",
stylelintReference: "https://stylelint.io/user-guide/rules/max-nesting-depth/",
})
}
root.walkRules(checkStatement)
root.walkAtRules(checkStatement)
function checkStatement(statement) {
if (isIgnoreAtRule(statement)) {
return
}
if (!hasBlock(statement)) {
return
}
const depth = nestingDepth(statement)
if (depth > max) {
report({
ruleName,
result,
node: statement,
message: messages.expected(max),
})
}
}
}
function nestingDepth(node, level) {
level = level || 0
const parent = node.parent
if (isIgnoreAtRule(parent)) {
return 0
}
// The nesting depth level's computation has finished
// when this function, recursively called, receives
// a node that is not nested -- a direct child of the
// root node
if (parent.type === "root" || parent.type === "atrule" && parent.parent.type === "root") {
return level
}
if (ignoreAtRulesWithoutDeclarationBlocks && node.type === "atrule" && node.every(child => child.type !== "decl")) {
return nestingDepth(parent, level)
}
// Unless any of the conditions above apply, we want to
// add 1 to the nesting depth level and then check the parent,
// continuing to add and move up the hierarchy
// until we hit the root node
return nestingDepth(parent, level + 1)
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 55.56% | (10 / 18) | 0% | (0 / 2) | 0% | (0 / 1) | 55.56% | (10 / 18) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const mediaFeatureColonSpaceChecker = require("../mediaFeatureColonSpaceChecker")
const ruleName = "media-feature-colon-space-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected single space after \":\"",
rejectedAfter: () => "Unexpected whitespace after \":\"",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
mediaFeatureColonSpaceChecker({
root,
result,
locationChecker: checker.after,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 55.56% | (10 / 18) | 0% | (0 / 2) | 0% | (0 / 1) | 55.56% | (10 / 18) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const mediaFeatureColonSpaceChecker = require("../mediaFeatureColonSpaceChecker")
const ruleName = "media-feature-colon-space-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected single space before \":\"",
rejectedBefore: () => "Unexpected whitespace before \":\"",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
mediaFeatureColonSpaceChecker({
root,
result,
locationChecker: checker.before,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 55.17% | (16 / 29) | 0% | (0 / 9) | 0% | (0 / 1) | 55.17% | (16 / 29) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../../utils/atRuleParamIndex")
const isCustomMediaQuery = require("../../utils/isCustomMediaQuery")
const isRangeContextMediaFeature = require("../../utils/isRangeContextMediaFeature")
const isStandardSyntaxMediaFeatureName = require("../../utils/isStandardSyntaxMediaFeatureName")
const matchesStringOrRegExp = require("../../utils/matchesStringOrRegExp")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const mediaParser = require("postcss-media-query-parser").default
const ruleName = "media-feature-name-blacklist"
const messages = ruleMessages(ruleName, {
rejected: name => `Unexpected media feature name "${name}"`,
})
const rule = function (blacklist) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: blacklist,
possible: [_.isString],
})
if (!validOptions) {
return
}
root.walkAtRules(/^media$/i, atRule => {
mediaParser(atRule.params).walk(/^media-feature$/i, mediaFeatureNode => {
const parent = mediaFeatureNode.parent,
sourceIndex = mediaFeatureNode.sourceIndex,
value = mediaFeatureNode.value
if (isRangeContextMediaFeature(parent.value) || !isStandardSyntaxMediaFeatureName(value) || isCustomMediaQuery(value)) {
return
}
if (!matchesStringOrRegExp(value.toLowerCase(), blacklist)) {
return
}
report({
index: atRuleParamIndex(atRule) + sourceIndex,
message: messages.rejected(value),
node: atRule,
ruleName,
result,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 50% | (14 / 28) | 0% | (0 / 11) | 0% | (0 / 1) | 50% | (14 / 28) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../../utils/atRuleParamIndex")
const isCustomMediaQuery = require("../../utils/isCustomMediaQuery")
const isRangeContextMediaFeature = require("../../utils/isRangeContextMediaFeature")
const isStandardSyntaxMediaFeatureName = require("../../utils/isStandardSyntaxMediaFeatureName")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const mediaParser = require("postcss-media-query-parser").default
const ruleName = "media-feature-name-case"
const messages = ruleMessages(ruleName, {
expected: (actual, expected) => `Expected "${actual}" to be "${expected}"`,
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"lower",
"upper",
],
})
if (!validOptions) {
return
}
root.walkAtRules(/^media$/i, atRule => {
mediaParser(atRule.params).walk(/^media-feature$/i, mediaFeatureNode => {
const parent = mediaFeatureNode.parent,
sourceIndex = mediaFeatureNode.sourceIndex,
value = mediaFeatureNode.value
if (isRangeContextMediaFeature(parent.value) || !isStandardSyntaxMediaFeatureName(value) || isCustomMediaQuery(value)) {
return
}
const expectedFeatureName = expectation === "lower" ? value.toLowerCase() : value.toUpperCase()
if (value === expectedFeatureName) {
return
}
report({
index: atRuleParamIndex(atRule) + sourceIndex,
message: messages.expected(value, expectedFeatureName),
node: atRule,
ruleName,
result,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 54.55% | (18 / 33) | 0% | (0 / 13) | 0% | (0 / 1) | 54.55% | (18 / 33) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../../utils/atRuleParamIndex")
const isCustomMediaQuery = require("../../utils/isCustomMediaQuery")
const isRangeContextMediaFeature = require("../../utils/isRangeContextMediaFeature")
const isStandardSyntaxMediaFeatureName = require("../../utils/isStandardSyntaxMediaFeatureName")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const keywordSets = require("../../reference/keywordSets")
const mediaParser = require("postcss-media-query-parser").default
const postcss = require("postcss")
const ruleName = "media-feature-name-no-unknown"
const messages = ruleMessages(ruleName, {
rejected: mediaFeatureName => `Unexpected unknown media feature name "${mediaFeatureName}"`,
})
const rule = function (actual, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual }, {
actual: options,
possible: {
ignoreMediaFeatureNames: [_.isString],
},
optional: true,
})
if (!validOptions) {
return
}
root.walkAtRules(/^media$/i, atRule => {
mediaParser(atRule.params).walk(/^media-feature$/i, mediaFeatureNode => {
const parent = mediaFeatureNode.parent,
sourceIndex = mediaFeatureNode.sourceIndex,
value = mediaFeatureNode.value
if (isRangeContextMediaFeature(parent.value) || !isStandardSyntaxMediaFeatureName(value) || isCustomMediaQuery(value)) {
return
}
if (optionsMatches(options, "ignoreMediaFeatureNames", value)) {
return
}
if (postcss.vendor.prefix(value) || keywordSets.mediaFeatureNames.has(value.toLowerCase())) {
return
}
report({
index: atRuleParamIndex(atRule) + sourceIndex,
message: messages.rejected(value),
node: atRule,
ruleName,
result,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 43.48% | (10 / 23) | 0% | (0 / 6) | 0% | (0 / 1) | 45.45% | (10 / 22) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isAutoprefixable = require("../../utils/isAutoprefixable")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "media-feature-name-no-vendor-prefix"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected vendor-prefix",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkAtRules(/^media$/i, atRule => {
const params = atRule.params
if (!isAutoprefixable.mediaFeatureName(params)) {
return
}
const matches = atRule.toString().match(/[a-z-]+device-pixel-ratio/ig)
if (!matches) { return }
matches.forEach(match => {
report({
message: messages.rejected,
node: atRule,
word: match,
result,
ruleName,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 55.17% | (16 / 29) | 0% | (0 / 9) | 0% | (0 / 1) | 55.17% | (16 / 29) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../../utils/atRuleParamIndex")
const isCustomMediaQuery = require("../../utils/isCustomMediaQuery")
const isRangeContextMediaFeature = require("../../utils/isRangeContextMediaFeature")
const isStandardSyntaxMediaFeatureName = require("../../utils/isStandardSyntaxMediaFeatureName")
const matchesStringOrRegExp = require("../../utils/matchesStringOrRegExp")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const mediaParser = require("postcss-media-query-parser").default
const ruleName = "media-feature-name-whitelist"
const messages = ruleMessages(ruleName, {
rejected: name => `Unexpected media feature name "${name}"`,
})
const rule = function (whitelist) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: whitelist,
possible: [_.isString],
})
if (!validOptions) {
return
}
root.walkAtRules(/^media$/i, atRule => {
mediaParser(atRule.params).walk(/^media-feature$/i, mediaFeatureNode => {
const parent = mediaFeatureNode.parent,
sourceIndex = mediaFeatureNode.sourceIndex,
value = mediaFeatureNode.value
if (isRangeContextMediaFeature(parent.value) || !isStandardSyntaxMediaFeatureName(value) || isCustomMediaQuery(value)) {
return
}
if (matchesStringOrRegExp(value.toLowerCase(), whitelist)) {
return
}
report({
index: atRuleParamIndex(atRule) + sourceIndex,
message: messages.rejected(value),
node: atRule,
ruleName,
result,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 37.21% | (16 / 43) | 0% | (0 / 18) | 0% | (0 / 4) | 37.21% | (16 / 43) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../../utils/atRuleParamIndex")
const isStandardSyntaxMediaFeature = require("../../utils/isStandardSyntaxMediaFeature")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const execall = require("execall")
const punctuationSets = require("../../reference/punctuationSets")
const ruleName = "media-feature-no-missing-punctuation"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected missing punctuation",
})
function isPunctuation(str) {
return punctuationSets.mediaFeaturePunctuation.has(str)
}
function endsWithPunctuation(str) {
return isPunctuation(str.slice(-1)) || isPunctuation(str.slice(-2))
}
function startsWithPunctuation(str) {
return isPunctuation(str[0]) || isPunctuation(str.slice(0, 2))
}
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
result.warn((
"'media-feature-no-missing-punctuation' has been deprecated and in 8.0 will be removed."
), {
stylelintType: "deprecation",
stylelintReference: "https://stylelint.io/user-guide/rules/media-feature-no-missing-punctuation/",
})
root.walkAtRules(/^media$/i, atRule => {
execall(/\((.*?)\)/g, atRule.params).forEach(mediaFeatureMatch => {
if (!isStandardSyntaxMediaFeature(mediaFeatureMatch.match)) {
return
}
const splitMediaFeature = mediaFeatureMatch.sub[0].trim().split(/\s+/)
if (splitMediaFeature.length === 1) {
return
}
// Ignore the last one
for (let i = 0, l = splitMediaFeature.length - 1; i < l; i++) {
const mediaFeaturePart = splitMediaFeature[i]
// This part is valid if it is punctuation,
// it ends with punctuation,
// the next part is punctuation,
// or the next part begins with punctuation
if (isPunctuation(mediaFeaturePart)) {
continue
}
if (endsWithPunctuation(mediaFeaturePart)) {
continue
}
const nextPart = splitMediaFeature[i + 1]
if (isPunctuation(nextPart)) {
continue
}
if (startsWithPunctuation(nextPart)) {
continue
}
return report({
result,
ruleName,
message: messages.rejected,
node: atRule,
index: atRuleParamIndex(atRule) + mediaFeatureMatch.index,
})
}
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 38.71% | (12 / 31) | 0% | (0 / 18) | 0% | (0 / 1) | 38.71% | (12 / 31) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../../utils/atRuleParamIndex")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const styleSearch = require("style-search")
const ruleName = "media-feature-parentheses-space-inside"
const messages = ruleMessages(ruleName, {
expectedOpening: "Expected single space after \"(\"",
rejectedOpening: "Unexpected whitespace after \"(\"",
expectedClosing: "Expected single space before \")\"",
rejectedClosing: "Unexpected whitespace before \")\"",
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
root.walkAtRules(/^media$/i, atRule => {
// If there are comments in the params, the complete string
// will be at atRule.raws.params.raw
const params = _.get(atRule, "raws.params.raw", atRule.params)
const indexBoost = atRuleParamIndex(atRule)
styleSearch({ source: params, target: "(" }, match => {
const nextCharIsSpace = params[match.startIndex + 1] === " "
if (nextCharIsSpace && expectation === "never") {
report({
message: messages.rejectedOpening,
node: atRule,
index: match.startIndex + 1 + indexBoost,
result,
ruleName,
})
}
if (!nextCharIsSpace && expectation === "always") {
report({
message: messages.expectedOpening,
node: atRule,
index: match.startIndex + 1 + indexBoost,
result,
ruleName,
})
}
})
styleSearch({ source: params, target: ")" }, match => {
const prevCharIsSpace = params[match.startIndex - 1] === " "
if (prevCharIsSpace && expectation === "never") {
report({
message: messages.rejectedClosing,
node: atRule,
index: match.startIndex - 1 + indexBoost,
result,
ruleName,
})
}
if (!prevCharIsSpace && expectation === "always") {
report({
message: messages.expectedClosing,
node: atRule,
index: match.startIndex - 1 + indexBoost,
result,
ruleName,
})
}
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 52% | (13 / 25) | 0% | (0 / 2) | 0% | (0 / 2) | 52% | (13 / 25) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../../utils/atRuleParamIndex")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const findMediaOperator = require("../findMediaOperator")
const ruleName = "media-feature-range-operator-space-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected single space after range operator",
rejectedAfter: () => "Unexpected whitespace after range operator",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
root.walkAtRules(/^media$/i, atRule => {
findMediaOperator(atRule, checkAfterOperator)
})
function checkAfterOperator(match, params, node) {
const endIndex = match.index + match[1].length
checker.after({
source: params,
index: endIndex,
err: m => {
report({
message: m,
node,
index: endIndex + atRuleParamIndex(node) + 1,
result,
ruleName,
})
},
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 54.17% | (13 / 24) | 0% | (0 / 2) | 0% | (0 / 2) | 54.17% | (13 / 24) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../../utils/atRuleParamIndex")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const findMediaOperator = require("../findMediaOperator")
const ruleName = "media-feature-range-operator-space-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected single space before range operator",
rejectedBefore: () => "Unexpected whitespace before range operator",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
root.walkAtRules(/^media$/i, atRule => {
findMediaOperator(atRule, checkBeforeOperator)
})
function checkBeforeOperator(match, params, node) {
// The extra `+ 1` is because the match itself contains
// the character before the operator
checker.before({
source: params,
index: match.index + 1,
err: m => {
report({
message: m,
node,
index: match.index + atRuleParamIndex(node),
result,
ruleName,
})
},
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 52.63% | (10 / 19) | 0% | (0 / 2) | 0% | (0 / 1) | 52.63% | (10 / 19) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const mediaQueryListCommaWhitespaceChecker = require("../mediaQueryListCommaWhitespaceChecker")
const ruleName = "media-query-list-comma-newline-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected newline after \",\"",
expectedAfterMultiLine: () => "Expected newline after \",\" in a multi-line list",
rejectedAfterMultiLine: () => "Unexpected whitespace after \",\" in a multi-line list",
})
const rule = function (expectation) {
const checker = whitespaceChecker("newline", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"always-multi-line",
"never-multi-line",
],
})
if (!validOptions) {
return
}
// Only check for the newline after the comma, while allowing
// arbitrary indentation after the newline
mediaQueryListCommaWhitespaceChecker({
root,
result,
locationChecker: checker.afterOneOnly,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 52.63% | (10 / 19) | 0% | (0 / 2) | 0% | (0 / 1) | 52.63% | (10 / 19) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const mediaQueryListCommaWhitespaceChecker = require("../mediaQueryListCommaWhitespaceChecker")
const ruleName = "media-query-list-comma-newline-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected newline before \",\"",
expectedBeforeMultiLine: () => "Expected newline before \",\" in a multi-line list",
rejectedBeforeMultiLine: () => "Unexpected whitespace before \",\" in a multi-line list",
})
const rule = function (expectation) {
const checker = whitespaceChecker("newline", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"always-multi-line",
"never-multi-line",
],
})
if (!validOptions) {
return
}
mediaQueryListCommaWhitespaceChecker({
root,
result,
locationChecker: checker.beforeAllowingIndentation,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 50% | (10 / 20) | 0% | (0 / 2) | 0% | (0 / 1) | 50% | (10 / 20) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const mediaQueryListCommaWhitespaceChecker = require("../mediaQueryListCommaWhitespaceChecker")
const ruleName = "media-query-list-comma-space-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected single space after \",\"",
rejectedAfter: () => "Unexpected whitespace after \",\"",
expectedAfterSingleLine: () => "Expected single space after \",\" in a single-line list",
rejectedAfterSingleLine: () => "Unexpected whitespace after \",\" in a single-line list",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-single-line",
"never-single-line",
],
})
if (!validOptions) {
return
}
mediaQueryListCommaWhitespaceChecker({
root,
result,
locationChecker: checker.after,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 50% | (10 / 20) | 0% | (0 / 2) | 0% | (0 / 1) | 50% | (10 / 20) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const mediaQueryListCommaWhitespaceChecker = require("../mediaQueryListCommaWhitespaceChecker")
const ruleName = "media-query-list-comma-space-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected single space before \",\"",
rejectedBefore: () => "Unexpected whitespace before \",\"",
expectedBeforeSingleLine: () => "Expected single space before \",\" in a single-line list",
rejectedBeforeSingleLine: () => "Unexpected whitespace before \",\" in a single-line list",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-single-line",
"never-single-line",
],
})
if (!validOptions) {
return
}
mediaQueryListCommaWhitespaceChecker({
root,
result,
locationChecker: checker.before,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 46.15% | (12 / 26) | 0% | (0 / 6) | 0% | (0 / 1) | 46.15% | (12 / 26) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const Result = require("postcss/lib/result")
const _ = require("lodash")
const stylehacks = require("stylehacks")
const ruleName = "no-browser-hacks"
const messages = ruleMessages(ruleName, {
rejected: (type, hack) => `Unexpected ${type} hack "${hack}"`,
})
const rule = function (on, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual: on }, {
optional: true,
actual: options,
possible: {
browsers: [_.isString],
},
})
if (!validOptions) {
return
}
result.warn((
`'${ruleName}' has been deprecated and in 8.0 will be removed. Use 'stylelint-no-browser-hacks' plugin instead.`
), {
stylelintType: "deprecation",
stylelintReference: `https://stylelint.io/user-guide/rules/${ruleName}/`,
})
const stylehacksOptions = { lint: true }
if (options && options.browsers) {
stylehacksOptions.browsers = options.browsers
}
const stylehacksResult = new Result()
stylehacks(stylehacksOptions)(root, stylehacksResult)
stylehacksResult.warnings().forEach(stylehacksWarning => {
const message = messages.rejected(stylehacksWarning.identifier, stylehacksWarning.hack)
report({
ruleName,
result,
message,
node: stylehacksWarning.node,
line: stylehacksWarning.line,
column: stylehacksWarning.column,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 35.19% | (19 / 54) | 0% | (0 / 12) | 0% | (0 / 3) | 35.85% | (19 / 53) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const specificity = require("specificity")
const findAtRuleContext = require("../../utils/findAtRuleContext")
const isCustomPropertySet = require("../../utils/isCustomPropertySet")
const nodeContextLookup = require("../../utils/nodeContextLookup")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const keywordSets = require("../../reference/keywordSets")
const resolvedNestedSelector = require("postcss-resolve-nested-selector")
const ruleName = "no-descending-specificity"
const messages = ruleMessages(ruleName, {
rejected: (b, a) => `Expected selector "${b}" to come before selector "${a}"`,
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
const selectorContextLookup = nodeContextLookup()
root.walkRules(rule => {
// Ignore custom property set `--foo: {};`
if (isCustomPropertySet(rule)) {
return
}
const comparisonContext = selectorContextLookup.getContext(rule, findAtRuleContext(rule))
rule.selectors.forEach(selector => {
const trimSelector = selector.trim()
// Ignore `.selector, { }`
if (trimSelector === "") {
return
}
// The edge-case of duplicate selectors will act acceptably
const index = rule.selector.indexOf(trimSelector)
// Resolve any nested selectors before checking
resolvedNestedSelector(selector, rule).forEach(resolvedSelector => {
parseSelector(resolvedSelector, result, rule, s => checkSelector(s, rule, index, comparisonContext))
})
})
})
function checkSelector(selectorNode, rule, sourceIndex, comparisonContext) {
const selector = selectorNode.toString()
const referenceSelectorNode = lastCompoundSelectorWithoutPseudoClasses(selectorNode)
const selectorSpecificity = specificity.calculate(selector)[0].specificityArray
const entry = { selector, specificity: selectorSpecificity }
if (!comparisonContext.has(referenceSelectorNode)) {
comparisonContext.set(referenceSelectorNode, [entry])
return
}
const priorComparableSelectors = comparisonContext.get(referenceSelectorNode)
priorComparableSelectors.forEach(priorEntry => {
if (specificity.compare(selectorSpecificity, priorEntry.specificity) === -1) {
report({
ruleName,
result,
node: rule,
message: messages.rejected(selector, priorEntry.selector),
index: sourceIndex,
})
}
})
priorComparableSelectors.push(entry)
}
}
}
function lastCompoundSelectorWithoutPseudoClasses(selectorNode) {
const nodesAfterLastCombinator = _.last(selectorNode.nodes[0].split(node => {
return node.type === "combinator"
}))
const nodesWithoutPseudoClasses = nodesAfterLastCombinator.filter(node => {
return node.type !== "pseudo" || keywordSets.pseudoElements.has(node.value.replace(/:/g, ""))
}).join("")
return nodesWithoutPseudoClasses.toString()
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 38.46% | (15 / 39) | 0% | (0 / 10) | 0% | (0 / 1) | 38.46% | (15 / 39) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const findAtRuleContext = require("../../utils/findAtRuleContext")
const isKeyframeRule = require("../../utils/isKeyframeRule")
const nodeContextLookup = require("../../utils/nodeContextLookup")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const normalizeSelector = require("normalize-selector")
const resolvedNestedSelector = require("postcss-resolve-nested-selector")
const ruleName = "no-duplicate-selectors"
const messages = ruleMessages(ruleName, {
rejected: (selector, firstDuplicateLine) => `Unexpected duplicate selector "${selector}", first used at line ${firstDuplicateLine}`,
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
// The top level of this map will be rule sources.
// Each source maps to another map, which maps rule parents to a set of selectors.
// This ensures that selectors are only checked against selectors
// from other rules that share the same parent and the same source.
const selectorContextLookup = nodeContextLookup()
root.walkRules(rule => {
if (isKeyframeRule(rule)) {
return
}
const contextSelectorSet = selectorContextLookup.getContext(rule, findAtRuleContext(rule))
const resolvedSelectors = rule.selectors.reduce((result, selector) => {
return _.union(result, resolvedNestedSelector(selector, rule))
}, [])
const normalizedSelectorList = resolvedSelectors.map(normalizeSelector)
const selectorLine = rule.source.start.line
// Complain if the same selector list occurs twice
// Sort the selectors list so that the order of the constituents
// doesn't matter
const sortedSelectorList = normalizedSelectorList.slice().sort().join(",")
if (contextSelectorSet.has(sortedSelectorList)) {
// If the selector isn't nested we can use its raw value; otherwise,
// we have to approximate something for the message -- which is close enough
const isNestedSelector = resolvedSelectors.join(",") !== rule.selectors.join(",")
const selectorForMessage = isNestedSelector ? resolvedSelectors.join(", ") : rule.selector
const previousDuplicatePosition = contextSelectorSet.get(sortedSelectorList)
return report({
result,
ruleName,
node: rule,
message: messages.rejected(selectorForMessage, previousDuplicatePosition),
})
}
contextSelectorSet.set(sortedSelectorList, selectorLine)
// Or complain if one selector list contains the same selector more than one
rule.selectors.forEach((selector, i) => {
if (_.includes(normalizedSelectorList.slice(0, i), normalizeSelector(selector))) {
report({
result,
ruleName,
node: rule,
message: messages.rejected(selector, selectorLine),
})
}
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 56.25% | (9 / 16) | 0% | (0 / 4) | 0% | (0 / 1) | 56.25% | (9 / 16) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 1 1 1 1 1 1 1 1 1 | "use strict"
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "no-empty-source"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected empty source",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
if (!/^\s*$/.test(root.toString())) {
return
}
report({
message: messages.rejected,
node: root,
result,
ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 50% | (13 / 26) | 0% | (0 / 8) | 0% | (0 / 1) | 50% | (13 / 26) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isOnlyWhitespace = require("../../utils/isOnlyWhitespace")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const styleSearch = require("style-search")
const ruleName = "no-eol-whitespace"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected whitespace at end of line",
})
const whitespacesToReject = new Set([
" ",
"\t",
])
const rule = function (on, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: on,
}, {
optional: true,
actual: options,
possible: {
ignore: ["empty-lines"],
},
})
if (!validOptions) {
return
}
const rootString = root.toString()
styleSearch({
source: rootString,
target: [
"\n",
"\r",
],
comments: "check",
}, match => {
// If the character before newline is not whitespace, ignore
if (!whitespacesToReject.has(rootString[match.startIndex - 1])) {
return
}
if (optionsMatches(options, "ignore", "empty-lines")) {
// If there is only whitespace between the previous newline and
// this newline, ignore
const lineBefore = rootString.substring(match.startIndex + 1, rootString.lastIndexOf("\n", match.startIndex - 1))
if (isOnlyWhitespace(lineBefore)) {
return
}
}
report({
message: messages.rejected,
node: root,
index: match.startIndex - 1,
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 21.54% | (14 / 65) | 0% | (0 / 45) | 0% | (0 / 3) | 21.54% | (14 / 65) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const hasEmptyBlock = require("../../utils/hasEmptyBlock")
const isCustomPropertySet = require("../../utils/isCustomPropertySet")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const styleSearch = require("style-search")
const ruleName = "no-extra-semicolons"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected extra semicolon",
})
function getOffsetByNode(node) {
const string = node.root().source.input.css
const nodeColumn = node.source.start.column
const nodeLine = node.source.start.line
let line = 1
let column = 1
let index = 0
for (let i = 0; i < string.length; i++) {
if (column === nodeColumn && nodeLine === line) {
index = i
break
}
if (string[i] === "\n") {
column = 1
line += 1
} else {
column += 1
}
}
return index
}
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
const rawAfterRoot = root.raws.after
if (rawAfterRoot && rawAfterRoot.trim().length !== 0) {
styleSearch({ source: rawAfterRoot, target: ";" }, match => {
complain(root.toString().length - rawAfterRoot.length + match.startIndex)
})
}
root.walk(node => {
let rawBeforeNode = node.raws.before
if (rawBeforeNode && rawBeforeNode.trim().length !== 0) {
let allowedSemi = 0
// Forbid semicolon before first custom properties sets
if (isCustomPropertySet(node) && node.parent.index(node) > 0) {
allowedSemi = 1
}
const next = node.next()
// Ignore semicolon before comment if next node is custom properties sets or comment
if (node.type === "comment" && next
&& (isCustomPropertySet(next) && node.parent.index(next) > 0 || next.type === "comment")
) {
allowedSemi = 1
}
const prev = node.prev()
// Adding previous node string to custom properties set if previous node is comment
if (isCustomPropertySet(node) && node.parent.index(node) > 0 && prev && prev.type === "comment") {
rawBeforeNode = prev.toString() + rawBeforeNode
allowedSemi = 0
}
styleSearch({ source: rawBeforeNode, target: ";" }, (match, count) => {
if (count === allowedSemi) {
return
}
complain(getOffsetByNode(node) - rawBeforeNode.length + match.startIndex)
})
}
const rawAfterNode = node.raws.after
if (rawAfterNode && rawAfterNode.trim().length !== 0) {
let allowedSemi = 0
if (!hasEmptyBlock(node) && isCustomPropertySet(node.nodes[node.nodes.length - 1])) {
allowedSemi = 1
}
styleSearch({ source: rawAfterNode, target: ";" }, (match, count) => {
if (count === allowedSemi) {
return
}
const index = getOffsetByNode(node) + node.toString().length - 1 - rawAfterNode.length + match.startIndex
complain(index)
})
}
})
function complain(index) {
report({
message: messages.rejected,
node: root,
index,
result,
ruleName,
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 50% | (13 / 26) | 0% | (0 / 7) | 0% | (0 / 1) | 50% | (13 / 26) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const isValidHex = require("../../utils/isValidHex")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const Result = require("postcss/lib/result")
const colorguard = require("colorguard")
const ruleName = "no-indistinguishable-colors"
const messages = ruleMessages(ruleName, {
rejected: (a, b) => `Unexpected indistinguishable colors "${a}" and "${b}"`,
})
const rule = function (on, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual: on }, {
optional: true,
actual: options,
possible: {
ignore: isValidHex,
threshold: x => _.isNumber(x) && x >= 0 && x <= 100,
whitelist: x => _.isArray(x) && x.every(isValidHex),
},
})
if (!validOptions) {
return
}
result.warn((
`'${ruleName}' has been deprecated and in 8.0 will be removed.`
), {
stylelintType: "deprecation",
stylelintReference: `https://stylelint.io/user-guide/rules/${ruleName}/`,
})
const colorguardResult = new Result()
colorguard(options)(root, colorguardResult)
colorguardResult.warnings().forEach(colorguardWarning => {
const message = messages.rejected(colorguardWarning.secondColor, colorguardWarning.firstColor)
report({
ruleName,
result,
message,
node: colorguardWarning.node,
index: colorguardWarning.node.toString().indexOf(colorguardWarning.secondColor),
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 45% | (9 / 20) | 0% | (0 / 6) | 0% | (0 / 1) | 45% | (9 / 20) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | 1 1 1 1 1 1 1 1 1 | "use strict"
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "no-invalid-double-slash-comments"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected double-slash CSS comment",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkDecls(decl => {
if (decl.prop.indexOf("//") === 0) {
report({
message: messages.rejected,
node: decl,
result,
ruleName,
})
}
})
root.walkRules(rule => {
rule.selectors.forEach(selector => {
if (selector.indexOf("//") === 0) {
report({
message: messages.rejected,
node: rule,
result,
ruleName,
})
}
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 52.94% | (9 / 17) | 0% | (0 / 6) | 0% | (0 / 1) | 52.94% | (9 / 17) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 1 1 1 1 1 1 1 1 1 | "use strict"
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "no-missing-end-of-source-newline"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected missing end-of-source newline",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
const sourceCss = root.source.input.css
if (sourceCss === "" || sourceCss.slice(-1) === "\n") {
return
}
report({
message: messages.rejected,
node: root,
index: sourceCss.length - 1,
result,
ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 38.71% | (12 / 31) | 0% | (0 / 12) | 0% | (0 / 1) | 38.71% | (12 / 31) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const declarationValueIndex = require("../../utils/declarationValueIndex")
const findAnimationName = require("../../utils/findAnimationName")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const keywordSets = require("../../reference/keywordSets")
const ruleName = "no-unknown-animations"
const messages = ruleMessages(ruleName, {
rejected: animationName => `Unexpected unknown animation name "${animationName}"`,
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
const declaredAnimations = new Set()
root.walkAtRules(/(-(moz|webkit)-)?keyframes/i, atRule => {
declaredAnimations.add(atRule.params)
})
root.walkDecls(decl => {
if (decl.prop.toLowerCase() === "animation" || decl.prop.toLowerCase() === "animation-name") {
const animationNames = findAnimationName(decl.value)
if (animationNames.length === 0) {
return
}
animationNames.forEach(animationNameNode => {
if (keywordSets.animationNameKeywords.has(animationNameNode.value.toLowerCase())) {
return
}
if (declaredAnimations.has(animationNameNode.value)) {
return
}
report({
result,
ruleName,
message: messages.rejected(animationNameNode.value),
node: decl,
index: declarationValueIndex(decl) + animationNameNode.sourceIndex,
})
})
}
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 39.39% | (13 / 33) | 0% | (0 / 12) | 0% | (0 / 2) | 39.39% | (13 / 33) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const doiuse = require("doiuse")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const Result = require("postcss/lib/result")
const _ = require("lodash")
const ruleName = "no-unsupported-browser-features"
const messages = ruleMessages(ruleName, {
rejected: details => `Unexpected browser feature ${details}`,
})
const rule = function (on, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual: on }, {
optional: true,
actual: options,
possible: {
browsers: [_.isString],
ignore: [_.isString],
},
})
if (!validOptions) {
return
}
result.warn((
`'${ruleName}' has been deprecated and in 8.0 will be removed.`
), {
stylelintType: "deprecation",
stylelintReference: `https://stylelint.io/user-guide/rules/${ruleName}/`,
})
const doiuseOptions = {}
if (options && options.browsers) {
doiuseOptions.browsers = options.browsers
}
if (options && options.ignore) {
doiuseOptions.ignore = options.ignore
}
const doiuseResult = new Result()
doiuse(doiuseOptions).postcss(root, doiuseResult)
doiuseResult.warnings().forEach(doiuseWarning => {
report({
ruleName,
result,
message: messages.rejected(cleanDoiuseWarningText(doiuseWarning.text)),
node: doiuseWarning.node,
line: doiuseWarning.line,
column: doiuseWarning.column,
})
})
}
}
function cleanDoiuseWarningText(warningText) {
// Get index of feature Id
const featureIdIndex = warningText.lastIndexOf("(")
// Get feature Id, then replace brackets with quotes
const featureId = warningText.slice(featureIdIndex, warningText.length).replace(/\(|\)/g, "\"")
// Get start of support text i.e. "x not supported by...", or "y only partially supported by..."
const browserSupportStartIndex = warningText.indexOf("not") !== -1 ? warningText.indexOf("not") : warningText.indexOf("only")
// Get browser support text, then strip brackets.
const browserSupport = warningText.slice(browserSupportStartIndex, featureIdIndex - 1).replace(/\(|\)|:/g, "")
return `${featureId} is ${browserSupport}`
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 31.82% | (14 / 44) | 0% | (0 / 20) | 0% | (0 / 3) | 32.56% | (14 / 43) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../../utils/atRuleParamIndex")
const declarationValueIndex = require("../../utils/declarationValueIndex")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const valueParser = require("postcss-value-parser")
const ruleName = "number-leading-zero"
const messages = ruleMessages(ruleName, {
expected: "Expected a leading zero",
rejected: "Unexpected leading zero",
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
root.walkAtRules(atRule => {
if (atRule.name.toLowerCase() === "import") {
return
}
check(atRule, atRule.params, atRuleParamIndex)
})
root.walkDecls(decl => check(decl, decl.value, declarationValueIndex))
function check(node, value, getIndex) {
// Get out quickly if there are no periods
if (value.indexOf(".") === -1) {
return
}
valueParser(value).walk(valueNode => {
// Ignore `url` function
if (valueNode.type === "function" && valueNode.value.toLowerCase() === "url") {
return false
}
// Ignore strings, comments, etc
if (valueNode.type !== "word") {
return
}
// Check leading zero
if (expectation === "always") {
const match = /(?:\D|^)(\.\d+)/.exec(valueNode.value)
if (match === null) {
return
}
// The regexp above consists of 2 capturing groups (or capturing parentheses).
// We need the index of the second group. This makes sanse when we have "-.5" as an input
// for regex. And we need the index of ".5".
const capturingGroupIndex = match[0].length - match[1].length
complain(messages.expected, node, getIndex(node) + valueNode.sourceIndex + match.index + capturingGroupIndex)
}
if (expectation === "never") {
const match = /(?:\D|^)(0+\.\d+)/.exec(valueNode.value)
if (match === null) {
return
}
const capturingGroupIndex = match[0].length - match[1].length
complain(messages.rejected, node, getIndex(node) + valueNode.sourceIndex + match.index + capturingGroupIndex)
}
})
}
function complain(message, node, index) {
report({
result,
ruleName,
message,
node,
index,
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 36.84% | (14 / 38) | 0% | (0 / 16) | 0% | (0 / 2) | 37.84% | (14 / 37) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../../utils/atRuleParamIndex")
const declarationValueIndex = require("../../utils/declarationValueIndex")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const valueParser = require("postcss-value-parser")
const ruleName = "number-max-precision"
const messages = ruleMessages(ruleName, {
expected: (number, precision) => `Expected "${number}" to be "${number.toFixed(precision)}"`,
})
const rule = function (precision) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: precision,
possible: [_.isNumber],
})
if (!validOptions) {
return
}
root.walkAtRules(atRule => {
if (atRule.name.toLowerCase() === "import") {
return
}
check(atRule, atRule.params, atRuleParamIndex)
})
root.walkDecls(decl => check(decl, decl.value, declarationValueIndex))
function check(node, value, getIndex) {
// Get out quickly if there are no periods
if (value.indexOf(".") === -1) {
return
}
valueParser(value).walk(valueNode => {
// Ignore `url` function
if (valueNode.type === "function" && valueNode.value.toLowerCase() === "url") {
return false
}
// Ignore strings, comments, etc
if (valueNode.type !== "word") {
return
}
const match = /\d*\.(\d+)/.exec(valueNode.value)
if (match === null) {
return
}
if (match[1].length <= precision) {
return
}
report({
result,
ruleName,
node,
index: getIndex(node) + valueNode.sourceIndex + match.index,
message: messages.expected(parseFloat(match[0]), precision),
})
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 38.24% | (13 / 34) | 0% | (0 / 14) | 0% | (0 / 2) | 39.39% | (13 / 33) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../../utils/atRuleParamIndex")
const declarationValueIndex = require("../../utils/declarationValueIndex")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const valueParser = require("postcss-value-parser")
const ruleName = "number-no-trailing-zeros"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected trailing zero(s)",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkAtRules(atRule => {
if (atRule.name.toLowerCase() === "import") {
return
}
check(atRule, atRule.params, atRuleParamIndex)
})
root.walkDecls(decl => check(decl, decl.value, declarationValueIndex))
function check(node, value, getIndex) {
// Get out quickly if there are no periods
if (value.indexOf(".") === -1) {
return
}
valueParser(value).walk(valueNode => {
// Ignore `url` function
if (valueNode.type === "function" && valueNode.value.toLowerCase() === "url") {
return false
}
// Ignore strings, comments, etc
if (valueNode.type !== "word") {
return
}
const match = /(\.\d*)0+(?:\D|$)/.exec(valueNode.value)
if (match === null) {
return
}
report({
message: messages.rejected,
node,
index: getIndex(node) + valueNode.sourceIndex + match.index + match[1].length,
result,
ruleName,
})
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 51.72% | (15 / 29) | 0% | (0 / 8) | 0% | (0 / 1) | 51.72% | (15 / 29) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isCustomProperty = require("../../utils/isCustomProperty")
const isStandardSyntaxProperty = require("../../utils/isStandardSyntaxProperty")
const matchesStringOrRegExp = require("../../utils/matchesStringOrRegExp")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const postcss = require("postcss")
const ruleName = "property-blacklist"
const messages = ruleMessages(ruleName, {
rejected: property => `Unexpected property "${property}"`,
})
const rule = function (blacklist) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: blacklist,
possible: [_.isString],
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const prop = decl.prop
if (!isStandardSyntaxProperty(prop)) {
return
}
if (isCustomProperty(prop)) {
return
}
if (!matchesStringOrRegExp(postcss.vendor.unprefixed(prop), blacklist)) {
return
}
report({
message: messages.rejected(prop),
node: decl,
result,
ruleName,
})
})
}
}
rule.primaryOptionArray = true
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 42.31% | (11 / 26) | 0% | (0 / 10) | 0% | (0 / 1) | 42.31% | (11 / 26) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isCustomProperty = require("../../utils/isCustomProperty")
const isStandardSyntaxProperty = require("../../utils/isStandardSyntaxProperty")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "property-case"
const messages = ruleMessages(ruleName, {
expected: (actual, expected) => `Expected "${actual}" to be "${expected}"`,
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"lower",
"upper",
],
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const prop = decl.prop
if (!isStandardSyntaxProperty(prop)) {
return
}
if (isCustomProperty(prop)) {
return
}
const expectedProp = expectation === "lower" ? prop.toLowerCase() : prop.toUpperCase()
if (prop === expectedProp) {
return
}
report({
message: messages.expected(prop, expectedProp),
node: decl,
ruleName,
result,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 43.24% | (16 / 37) | 0% | (0 / 16) | 0% | (0 / 1) | 43.24% | (16 / 37) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isCustomProperty = require("../../utils/isCustomProperty")
const isStandardSyntaxDeclaration = require("../../utils/isStandardSyntaxDeclaration")
const isStandardSyntaxProperty = require("../../utils/isStandardSyntaxProperty")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const properties = require("known-css-properties").all
const postcss = require("postcss")
const ruleName = "property-no-unknown"
const messages = ruleMessages(ruleName, {
rejected: property => `Unexpected unknown property "${property}"`,
})
const rule = function (actual, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual }, {
actual: options,
possible: {
ignoreProperties: [_.isString],
checkPrefixed: _.isBoolean,
},
optional: true,
})
if (!validOptions) {
return
}
const shouldCheckPrefixed = _.get(options, "checkPrefixed")
root.walkDecls(decl => {
const prop = decl.prop
if (!isStandardSyntaxProperty(prop)) {
return
}
if (!isStandardSyntaxDeclaration(decl)) {
return
}
if (isCustomProperty(prop)) {
return
}
if (!shouldCheckPrefixed && postcss.vendor.prefix(prop)) {
return
}
if (optionsMatches(options, "ignoreProperties", prop)) {
return
}
if (properties.indexOf(prop.toLowerCase()) !== -1) {
return
}
report({
message: messages.rejected(prop),
node: decl,
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 45.45% | (10 / 22) | 0% | (0 / 8) | 0% | (0 / 1) | 45.45% | (10 / 22) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isAutoprefixable = require("../../utils/isAutoprefixable")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "property-no-vendor-prefix"
const messages = ruleMessages(ruleName, {
rejected: property => `Unexpected vendor-prefix "${property}"`,
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkDecls(decl => {
const prop = decl.prop
// Make sure there's a vendor prefix,
// but this isn't a custom property
if (prop[0] !== "-" || prop[1] === "-") {
return
}
if (!isAutoprefixable.property(prop)) {
return
}
report({
message: messages.rejected(prop),
node: decl,
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 51.72% | (15 / 29) | 0% | (0 / 8) | 0% | (0 / 1) | 51.72% | (15 / 29) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isCustomProperty = require("../../utils/isCustomProperty")
const isStandardSyntaxProperty = require("../../utils/isStandardSyntaxProperty")
const matchesStringOrRegExp = require("../../utils/matchesStringOrRegExp")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const postcss = require("postcss")
const ruleName = "property-whitelist"
const messages = ruleMessages(ruleName, {
rejected: property => `Unexpected property "${property}"`,
})
const rule = function (whitelist) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: whitelist,
possible: [_.isString],
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const prop = decl.prop
if (!isStandardSyntaxProperty(prop)) {
return
}
if (isCustomProperty(prop)) {
return
}
if (matchesStringOrRegExp(postcss.vendor.unprefixed(prop), whitelist)) {
return
}
report({
message: messages.rejected(prop),
node: decl,
result,
ruleName,
})
})
}
}
rule.primaryOptionArray = true
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 35% | (14 / 40) | 0% | (0 / 18) | 0% | (0 / 4) | 35% | (14 / 40) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isCustomProperty = require("../../utils/isCustomProperty")
const isStandardSyntaxProperty = require("../../utils/isStandardSyntaxProperty")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "root-no-standard-properties"
const messages = ruleMessages(ruleName, {
rejected: property => `Unexpected standard property "${property}"`,
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
result.warn((
`'${ruleName}' has been deprecated and in 8.0 will be removed. Instead use the community 'stylelint-suitcss' plugin pack.`
), {
stylelintType: "deprecation",
stylelintReference: `https://stylelint.io/user-guide/rules/${ruleName}/`,
})
root.walkRules(rule => {
if (rule.selector.toLowerCase().indexOf(":root") === -1) {
return
}
parseSelector(rule.selector, result, rule, checkSelector)
function checkSelector(selectorAST) {
if (ignoreRule(selectorAST)) {
return
}
rule.each(function (node) {
if (node.type !== "decl") {
return
}
const prop = node.prop
if (!isStandardSyntaxProperty(prop)) {
return
}
if (isCustomProperty(prop)) {
return
}
report({
message: messages.rejected(prop),
node,
result,
ruleName,
})
})
}
})
}
}
function ignoreRule(selectorAST) {
let ignore = false
selectorAST.walk(selectorNode => {
// ignore `:root` selector inside a `:not()` selector
if (selectorNode.value && selectorNode.value.toLowerCase() === ":root" && selectorNode.parent.parent.value && selectorNode.parent.parent.value.toLowerCase() === ":not") {
ignore = true
}
})
return ignore
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 30.95% | (13 / 42) | 0% | (0 / 46) | 0% | (0 / 1) | 30.95% | (13 / 42) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const hasEmptyLine = require("../../utils/hasEmptyLine")
const isSingleLineString = require("../../utils/isSingleLineString")
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "rule-empty-line-before"
const messages = ruleMessages(ruleName, {
expected: "Expected empty line before rule",
rejected: "Unexpected empty line before rule",
})
const rule = function (expectation, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-multi-line",
"never-multi-line",
],
}, {
actual: options,
possible: {
ignore: [
"after-comment",
"inside-block",
],
except: [
"after-rule",
"after-single-line-comment",
"first-nested",
"inside-block-and-after-rule",
],
},
optional: true,
})
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
// Ignore the first node
if (rule === root.first) {
return
}
let expectEmptyLineBefore = expectation.indexOf("always") !== -1 ? true : false
// Optionally ignore the expectation if a comment precedes this node
if (
optionsMatches(options, "ignore", "after-comment")
&& rule.prev()
&& rule.prev().type === "comment"
) {
return
}
// Optionally ignore the expectation if inside a block
if (
optionsMatches(options, "ignore", "inside-block")
&& rule.parent !== root
) {
return
}
// Ignore if the expectation is for multiple and the rule is single-line
if (
expectation.indexOf("multi-line") !== -1
&& isSingleLineString(rule.toString())
) {
return
}
// Optionally reverse the expectation for the first nested node
if (
optionsMatches(options, "except", "first-nested")
&& rule === rule.parent.first
) {
expectEmptyLineBefore = !expectEmptyLineBefore
}
// Optionally reverse the expectation if a rule precedes this node
if (
optionsMatches(options, "except", "after-rule")
&& rule.prev()
&& rule.prev().type === "rule"
) {
expectEmptyLineBefore = !expectEmptyLineBefore
}
// Optionally reverse the expectation if a rule precedes this node and is inside a block
if (
optionsMatches(options, "except", "inside-block-and-after-rule")
&& rule.prev()
&& rule.prev().type === "rule"
&& rule.parent !== root
) {
expectEmptyLineBefore = !expectEmptyLineBefore
}
// Optionally reverse the expectation for single line comments
if (
optionsMatches(options, "except", "after-single-line-comment")
&& rule.prev()
&& rule.prev().type === "comment"
&& isSingleLineString(rule.prev().toString())
) {
expectEmptyLineBefore = !expectEmptyLineBefore
}
const hasEmptyLineBefore = hasEmptyLine(rule.raws.before)
// Return if the expectation is met
if (expectEmptyLineBefore === hasEmptyLineBefore) {
return
}
const message = expectEmptyLineBefore ? messages.expected : messages.rejected
report({
message,
node: rule,
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 47.62% | (10 / 21) | 0% | (0 / 6) | 0% | (0 / 1) | 47.62% | (10 / 21) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const checkRuleEmptyLineBefore = require("../checkRuleEmptyLineBefore")
const ruleName = "rule-nested-empty-line-before"
const messages = ruleMessages(ruleName, {
expected: "Expected empty line before nested rule",
rejected: "Unexpected empty line before nested rule",
})
const rule = function (expectation, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-multi-line",
"never-multi-line",
],
}, {
actual: options,
possible: {
ignore: ["after-comment"],
except: [
"first-nested",
"after-comment",
"after-rule",
],
},
optional: true,
})
if (!validOptions) {
return
}
result.warn((
`'${ruleName}' has been deprecated and in 8.0 will be removed. Instead use 'rule-empty-line-before'.`
), {
stylelintType: "deprecation",
stylelintReference: `https://stylelint.io/user-guide/rules/${ruleName}/`,
})
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
// Only attend to nested rule sets
if (rule.parent === root) {
return
}
checkRuleEmptyLineBefore({ rule, expectation, options, result, messages, checkedRuleName: ruleName })
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 43.48% | (10 / 23) | 0% | (0 / 8) | 0% | (0 / 1) | 43.48% | (10 / 23) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const checkRuleEmptyLineBefore = require("../checkRuleEmptyLineBefore")
const ruleName = "rule-non-nested-empty-line-before"
const messages = ruleMessages(ruleName, {
expected: "Expected empty line before non-nested rule",
rejected: "Unexpected empty line before non-nested rule",
})
const rule = function (expectation, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-multi-line",
"never-multi-line",
],
}, {
actual: options,
possible: {
ignore: ["after-comment"],
except: ["after-single-line-comment"],
},
optional: true,
})
if (!validOptions) {
return
}
result.warn((
`'${ruleName}' has been deprecated and in 8.0 will be removed. Instead use 'rule-empty-line-before'.`
), {
stylelintType: "deprecation",
stylelintReference: `https://stylelint.io/user-guide/rules/${ruleName}/`,
})
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
// Ignore nested rule sets
if (rule.parent !== root) {
return
}
// Ignore the first node
if (rule === root.first) {
return
}
checkRuleEmptyLineBefore({ rule, expectation, options, result, messages, checkedRuleName: ruleName })
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 32.5% | (13 / 40) | 0% | (0 / 22) | 0% | (0 / 2) | 32.5% | (13 / 40) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const styleSearch = require("style-search")
const ruleName = "selector-attribute-brackets-space-inside"
const messages = ruleMessages(ruleName, {
expectedOpening: "Expected single space after \"[\"",
rejectedOpening: "Unexpected whitespace after \"[\"",
expectedClosing: "Expected single space before \"]\"",
rejectedClosing: "Unexpected whitespace before \"]\"",
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
if (rule.selector.indexOf("[") === -1) {
return
}
parseSelector(rule.selector, result, rule, selectorTree => {
selectorTree.walkAttributes(attributeNode => {
const attributeSelectorString = attributeNode.toString()
styleSearch({ source: attributeSelectorString, target: "[" }, match => {
const nextCharIsSpace = attributeSelectorString[match.startIndex + 1] === " "
const index = attributeNode.sourceIndex + match.startIndex + 1
if (nextCharIsSpace && expectation === "never") {
complain(messages.rejectedOpening, index)
}
if (!nextCharIsSpace && expectation === "always") {
complain(messages.expectedOpening, index)
}
})
styleSearch({ source: attributeSelectorString, target: "]" }, match => {
const prevCharIsSpace = attributeSelectorString[match.startIndex - 1] === " "
const index = attributeNode.sourceIndex + match.startIndex - 1
if (prevCharIsSpace && expectation === "never") {
complain(messages.rejectedClosing, index)
}
if (!prevCharIsSpace && expectation === "always") {
complain(messages.expectedClosing, index)
}
})
})
})
function complain(message, index) {
report({
message,
index,
result,
ruleName,
node: rule,
})
}
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 43.33% | (13 / 30) | 0% | (0 / 13) | 0% | (0 / 1) | 43.33% | (13 / 30) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const ruleName = "selector-attribute-operator-blacklist"
const messages = ruleMessages(ruleName, {
rejected: operator => `Unexpected operator "${operator}"`,
})
const rule = function (blacklistInput) {
const blacklist = [].concat(blacklistInput)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: blacklist,
possible: [_.isString],
})
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
if (rule.selector.indexOf("[") === -1 || rule.selector.indexOf("=") === -1) {
return
}
parseSelector(rule.selector, result, rule, selectorTree => {
selectorTree.walkAttributes(attributeNode => {
const operator = attributeNode.operator
if (!operator || operator && blacklist.indexOf(operator) === -1) {
return
}
report({
message: messages.rejected(operator),
node: rule,
index: attributeNode.attribute.length + 1,
result,
ruleName,
})
})
})
})
}
}
rule.primaryOptionArray = true
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 55.56% | (10 / 18) | 0% | (0 / 2) | 0% | (0 / 1) | 55.56% | (10 / 18) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const selectorAttributeOperatorSpaceChecker = require("../selectorAttributeOperatorSpaceChecker")
const ruleName = "selector-attribute-operator-space-after"
const messages = ruleMessages(ruleName, {
expectedAfter: operator => `Expected single space after "${operator}"`,
rejectedAfter: operator => `Unexpected whitespace after "${operator}"`,
})
const rule = function (expectation) {
return (root, result) => {
const checker = whitespaceChecker("space", expectation, messages)
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
selectorAttributeOperatorSpaceChecker({
root,
result,
locationChecker: checker.after,
checkedRuleName: ruleName,
checkBeforeOperator: false,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 55.56% | (10 / 18) | 0% | (0 / 2) | 0% | (0 / 1) | 55.56% | (10 / 18) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const selectorAttributeOperatorSpaceChecker = require("../selectorAttributeOperatorSpaceChecker")
const ruleName = "selector-attribute-operator-space-before"
const messages = ruleMessages(ruleName, {
expectedBefore: operator => `Expected single space before "${operator}"`,
rejectedBefore: operator => `Unexpected whitespace before "${operator}"`,
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
selectorAttributeOperatorSpaceChecker({
root,
result,
locationChecker: checker.before,
checkedRuleName: ruleName,
checkBeforeOperator: true,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 43.33% | (13 / 30) | 0% | (0 / 13) | 0% | (0 / 1) | 43.33% | (13 / 30) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const ruleName = "selector-attribute-operator-whitelist"
const messages = ruleMessages(ruleName, {
rejected: operator => `Unexpected operator "${operator}"`,
})
const rule = function (whitelistInput) {
const whitelist = [].concat(whitelistInput)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: whitelist,
possible: [_.isString],
})
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
if (rule.selector.indexOf("[") === -1 || rule.selector.indexOf("=") === -1) {
return
}
parseSelector(rule.selector, result, rule, selectorTree => {
selectorTree.walkAttributes(attributeNode => {
const operator = attributeNode.operator
if (!operator || operator && whitelist.indexOf(operator) !== -1) {
return
}
report({
message: messages.rejected(operator),
node: rule,
index: attributeNode.attribute.length + 1,
result,
ruleName,
})
})
})
})
}
}
rule.primaryOptionArray = true
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 36.36% | (12 / 33) | 0% | (0 / 18) | 0% | (0 / 2) | 36.36% | (12 / 33) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "selector-attribute-quotes"
const messages = ruleMessages(ruleName, {
expected: value => `Expected quotes around "${value}"`,
rejected: value => `Unexpected quotes around "${value}"`,
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
if (rule.selector.indexOf("[") === -1 || rule.selector.indexOf("=") === -1) {
return
}
parseSelector(rule.selector, result, rule, selectorTree => {
selectorTree.walkAttributes(attributeNode => {
if (!attributeNode.operator) {
return
}
const attributeSelectorString = attributeNode.toString()
if (!attributeNode.quoted && expectation === "always") {
complain(messages.expected(attributeNode.raws.unquoted), attributeNode.sourceIndex + attributeSelectorString.indexOf(attributeNode.value))
}
if (attributeNode.quoted && expectation === "never") {
complain(messages.rejected(attributeNode.raws.unquoted), attributeNode.sourceIndex + attributeSelectorString.indexOf(attributeNode.value))
}
})
})
function complain(message, index) {
report({
message,
index,
result,
ruleName,
node: rule,
})
}
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 32.14% | (18 / 56) | 0% | (0 / 28) | 0% | (0 / 4) | 33.96% | (18 / 53) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isKeyframeSelector = require("../../utils/isKeyframeSelector")
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const resolveNestedSelector = require("postcss-resolve-nested-selector")
const ruleName = "selector-class-pattern"
const messages = ruleMessages(ruleName, {
expected: selectorValue => `Expected class selector ".${selectorValue}" to match specified pattern`,
})
const rule = function (pattern, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: pattern,
possible: [
_.isRegExp,
_.isString,
],
}, {
actual: options,
possible: {
resolveNestedSelectors: _.isBoolean,
},
optional: true,
})
if (!validOptions) {
return
}
const shouldResolveNestedSelectors = _.get(options, "resolveNestedSelectors")
const normalizedPattern = _.isString(pattern) ? new RegExp(pattern) : pattern
root.walkRules(rule => {
const selector = rule.selector,
selectors = rule.selectors
if (!isStandardSyntaxRule(rule)) {
return
}
if (!isStandardSyntaxSelector(selector)) {
return
}
if (selectors.some(s => isKeyframeSelector(s))) {
return
}
// Only bother resolving selectors that have an interpolating &
if (shouldResolveNestedSelectors && hasInterpolatingAmpersand(selector)) {
resolveNestedSelector(selector, rule).forEach(selector => {
if (!isStandardSyntaxSelector(selector)) {
return
}
parseSelector(selector, result, rule, s => checkSelector(s, rule))
})
} else {
parseSelector(selector, result, rule, s => checkSelector(s, rule))
}
})
function checkSelector(fullSelector, rule) {
fullSelector.walkClasses(classNode => {
const value = classNode.value,
sourceIndex = classNode.sourceIndex
if (normalizedPattern.test(value)) {
return
}
report({
result,
ruleName,
message: messages.expected(value),
node: rule,
index: sourceIndex,
})
})
}
}
}
// An "interpolating ampersand" means an "&" used to interpolate
// within another simple selector, rather than an "&" that
// stands on its own as a simple selector
function hasInterpolatingAmpersand(selector) {
for (let i = 0, l = selector.length; i < l; i++) {
if (selector[i] !== "&") {
continue
}
if (!_.isUndefined(selector[i - 1]) && !isCombinator(selector[i - 1])) {
return true
}
if (!_.isUndefined(selector[i + 1]) && !isCombinator(selector[i + 1])) {
return true
}
}
return false
}
function isCombinator(x) {
return (/[\s+>~]/.test(x)
)
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 55.56% | (10 / 18) | 0% | (0 / 2) | 0% | (0 / 1) | 55.56% | (10 / 18) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const selectorCombinatorSpaceChecker = require("../selectorCombinatorSpaceChecker")
const ruleName = "selector-combinator-space-after"
const messages = ruleMessages(ruleName, {
expectedAfter: combinator => `Expected single space after "${combinator}"`,
rejectedAfter: combinator => `Unexpected whitespace after "${combinator}"`,
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
selectorCombinatorSpaceChecker({
root,
result,
locationChecker: checker.after,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 55.56% | (10 / 18) | 0% | (0 / 2) | 0% | (0 / 1) | 55.56% | (10 / 18) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const selectorCombinatorSpaceChecker = require("../selectorCombinatorSpaceChecker")
const ruleName = "selector-combinator-space-before"
const messages = ruleMessages(ruleName, {
expectedBefore: combinator => `Expected single space before "${combinator}"`,
rejectedBefore: combinator => `Unexpected whitespace before "${combinator}"`,
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
selectorCombinatorSpaceChecker({
root,
result,
locationChecker: checker.before,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 41.38% | (12 / 29) | 0% | (0 / 8) | 0% | (0 / 1) | 41.38% | (12 / 29) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const punctuationSets = require("../../reference/punctuationSets")
const ruleName = "selector-descendant-combinator-no-non-space"
const messages = ruleMessages(ruleName, {
rejected: nonSpaceCharacter => `Unexpected "${nonSpaceCharacter}"`,
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
const selector = rule.selector
parseSelector(selector, result, rule, fullSelector => {
fullSelector.walkCombinators(combinatorNode => {
const value = combinatorNode.value
if (punctuationSets.nonSpaceCombinators.has(value)) {
return
}
if (value === " ") {
return
}
report({
result,
ruleName,
message: messages.rejected(value),
node: rule,
index: combinatorNode.sourceIndex,
})
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 39.39% | (13 / 33) | 0% | (0 / 12) | 0% | (0 / 1) | 39.39% | (13 / 33) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "selector-id-pattern"
const messages = ruleMessages(ruleName, {
expected: selectorValue => `Expected id selector "#${selectorValue}" to match specified pattern`,
})
const rule = function (pattern) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: pattern,
possible: [
_.isRegExp,
_.isString,
],
})
if (!validOptions) {
return
}
const normalizedPattern = _.isString(pattern) ? new RegExp(pattern) : pattern
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
const selector = rule.selector
if (!isStandardSyntaxSelector(selector)) {
return
}
parseSelector(selector, result, rule, fullSelector => {
fullSelector.walk(selectorNode => {
if (selectorNode.type !== "id") {
return
}
const value = selectorNode.value,
sourceIndex = selectorNode.sourceIndex
if (normalizedPattern.test(value)) {
return
}
report({
result,
ruleName,
message: messages.expected(value),
node: rule,
index: sourceIndex,
})
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 38.71% | (12 / 31) | 0% | (0 / 10) | 0% | (0 / 1) | 38.71% | (12 / 31) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const styleSearch = require("style-search")
const ruleName = "selector-list-comma-newline-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected newline after \",\"",
expectedAfterMultiLine: () => "Expected newline after \",\" in a multi-line list",
rejectedAfterMultiLine: () => "Unexpected whitespace after \",\" in a multi-line list",
})
const rule = function (expectation) {
const checker = whitespaceChecker("newline", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"always-multi-line",
"never-multi-line",
],
})
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
// Get raw selector so we can allow end-of-line comments, e.g.
// a, /* comment */
// b {}
const selector = rule.raws.selector ? rule.raws.selector.raw : rule.selector
styleSearch({
source: selector,
target: ",",
functionArguments: "skip",
}, match => {
const nextThreeChars = selector.substr(match.endIndex, 3)
// If there's a // comment, that means there has to be a newline
// ending the comment so we're fine
if (nextThreeChars === " //") {
return
}
// If there is a space and then a comment begins, look for the newline
// after that comment
const indextoCheckAfter = nextThreeChars === " /*" ? selector.indexOf("*/", match.endIndex) + 1 : match.startIndex
checker.afterOneOnly({
source: selector,
index: indextoCheckAfter,
err: m => report({
message: m,
node: rule,
index: match.startIndex,
result,
ruleName,
}),
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 52.63% | (10 / 19) | 0% | (0 / 2) | 0% | (0 / 1) | 52.63% | (10 / 19) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const selectorListCommaWhitespaceChecker = require("../selectorListCommaWhitespaceChecker")
const ruleName = "selector-list-comma-newline-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected newline before \",\"",
expectedBeforeMultiLine: () => "Expected newline before \",\" in a multi-line list",
rejectedBeforeMultiLine: () => "Unexpected whitespace before \",\" in a multi-line list",
})
const rule = function (expectation) {
const checker = whitespaceChecker("newline", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"always-multi-line",
"never-multi-line",
],
})
if (!validOptions) {
return
}
selectorListCommaWhitespaceChecker({
root,
result,
locationChecker: checker.beforeAllowingIndentation,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 50% | (10 / 20) | 0% | (0 / 2) | 0% | (0 / 1) | 50% | (10 / 20) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const selectorListCommaWhitespaceChecker = require("../selectorListCommaWhitespaceChecker")
const ruleName = "selector-list-comma-space-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected single space after \",\"",
rejectedAfter: () => "Unexpected whitespace after \",\"",
expectedAfterSingleLine: () => "Expected single space after \",\" in a single-line list",
rejectedAfterSingleLine: () => "Unexpected whitespace after \",\" in a single-line list",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-single-line",
"never-single-line",
],
})
if (!validOptions) {
return
}
selectorListCommaWhitespaceChecker({
root,
result,
locationChecker: checker.after,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 50% | (10 / 20) | 0% | (0 / 2) | 0% | (0 / 1) | 50% | (10 / 20) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const selectorListCommaWhitespaceChecker = require("../selectorListCommaWhitespaceChecker")
const ruleName = "selector-list-comma-space-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected single space before \",\"",
rejectedBefore: () => "Unexpected whitespace before \",\"",
expectedBeforeSingleLine: () => "Expected single space before \",\" in a single-line list",
rejectedBeforeSingleLine: () => "Unexpected whitespace before \",\" in a single-line list",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-single-line",
"never-single-line",
],
})
if (!validOptions) {
return
}
selectorListCommaWhitespaceChecker({
root,
result,
locationChecker: checker.before,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 35% | (14 / 40) | 0% | (0 / 23) | 0% | (0 / 3) | 36.84% | (14 / 38) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const resolvedNestedSelector = require("postcss-resolve-nested-selector")
const selectorParser = require("postcss-selector-parser")
const ruleName = "selector-max-compound-selectors"
const messages = ruleMessages(ruleName, {
expected: (selector, max) => `Expected "${selector}" to have no more than ${max} compound selectors`,
})
const rule = function (max) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: max,
possible: [
function (max) {
return typeof max === "number" && max > 0
},
],
})
if (!validOptions) {
return
}
// Finds actual selectors in selectorNode object and checks them
function checkSelector(selectorNode, rule) {
let compoundCount = 1
selectorNode.each(childNode => {
// Only traverse inside actual selectors and :not()
if (childNode.type === "selector" || childNode.value === ":not") {
checkSelector(childNode, rule)
}
// Compound selectors are separated by combinators, so increase count when meeting one
if (childNode.type === "combinator") {
compoundCount++
}
})
if (selectorNode.type !== "root" && selectorNode.type !== "pseudo" && compoundCount > max) {
report({
ruleName,
result,
node: rule,
message: messages.expected(selectorNode, max),
word: selectorNode,
})
}
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
if (!isStandardSyntaxSelector(rule.selector)) {
return
}
// Nested selectors are processed in steps, as nesting levels are resolved.
// Here we skip processing the intermediate parts of selectors (to process only fully resolved selectors)
if (rule.nodes.some(node => node.type === "rule" || node.type === "atrule")) {
return
}
// Using `rule.selectors` gets us each selector if there is a comma separated set
rule.selectors.forEach(selector => {
resolvedNestedSelector(selector, rule).forEach(resolvedSelector => {
// Process each resolved selector with `checkSelector` via postcss-selector-parser
selectorParser(s => checkSelector(s, rule)).process(resolvedSelector)
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 40.74% | (11 / 27) | 0% | (0 / 10) | 0% | (0 / 1) | 40.74% | (11 / 27) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const styleSearch = require("style-search")
const ruleName = "selector-max-empty-lines"
const messages = ruleMessages(ruleName, {
expected: max => `Expected no more than ${max} empty line(s)`,
})
const rule = function (max) {
const maxAdjacentNewlines = max + 1
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: max,
possible: _.isNumber,
})
if (!validOptions) {
return
}
root.walkRules(rule => {
const selector = rule.raws.selector ? rule.raws.selector.raw : rule.selector
const repeatLFNewLines = _.repeat("\n", maxAdjacentNewlines)
const repeatCRLFNewLines = _.repeat("\r\n", maxAdjacentNewlines)
styleSearch({ source: selector, target: "\n" }, match => {
if (selector.substr(match.startIndex + 1, maxAdjacentNewlines) === repeatLFNewLines || selector.substr(match.startIndex + 1, maxAdjacentNewlines * 2) === repeatCRLFNewLines) {
// Put index at `\r` if it's CRLF, otherwise leave it at `\n`
let index = match.startIndex
if (selector[index - 1] === "\r") {
index -= 1
}
report({
message: messages.expected(max),
node: rule,
index,
result,
ruleName,
})
}
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 36.11% | (13 / 36) | 0% | (0 / 12) | 0% | (0 / 2) | 36.11% | (13 / 36) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const specificity = require("specificity")
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const resolvedNestedSelector = require("postcss-resolve-nested-selector")
const ruleName = "selector-max-specificity"
const messages = ruleMessages(ruleName, {
expected: (selector, specificity) => `Expected "${selector}" to have a specificity no more than "${specificity}"`,
})
const rule = function (max) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: max,
possible: [
function (max) {
// Check that the max specificity is in the form "a,b,c"
const pattern = new RegExp("^\\d+,\\d+,\\d+$")
return pattern.test(max)
},
],
})
if (!validOptions) {
return
}
const maxSpecificityArray = ("0," + max).split(",").map(parseFloat)
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
if (!isStandardSyntaxSelector(rule.selector)) {
return
}
// Using rule.selectors gets us each selector in the eventuality we have a comma separated set
rule.selectors.forEach(selector => {
resolvedNestedSelector(selector, rule).forEach(resolvedSelector => {
// Return early if selector contains a not pseudo-class
if (selector.indexOf(":not(") !== -1) {
return
}
// Return early if selector contains a matches
if (selector.indexOf(":matches(") !== -1) {
return
}
// Check if the selector specificity exceeds the allowed maximum
try {
if (specificity.compare(resolvedSelector, maxSpecificityArray) === 1) {
report({
ruleName,
result,
node: rule,
message: messages.expected(resolvedSelector, max),
word: selector,
})
}
} catch (e) {
result.warn("Cannot parse selector", { node: rule })
}
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 41.38% | (12 / 29) | 0% | (0 / 12) | 0% | (0 / 1) | 41.38% | (12 / 29) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "selector-nested-pattern"
const messages = ruleMessages(ruleName, {
expected: selector => `Expected nested selector "${selector}" to match specified pattern`,
})
const rule = function (pattern) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: pattern,
possible: [
_.isRegExp,
_.isString,
],
})
if (!validOptions) {
return
}
const normalizedPattern = _.isString(pattern) ? new RegExp(pattern) : pattern
root.walkRules(rule => {
if (rule.parent.type !== "rule") {
return
}
if (!isStandardSyntaxRule(rule)) {
return
}
const selector = rule.selector
if (!isStandardSyntaxSelector(selector)) {
return
}
if (normalizedPattern.test(selector)) {
return
}
report({
result,
ruleName,
message: messages.expected(selector),
node: rule,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 48% | (12 / 25) | 0% | (0 / 6) | 0% | (0 / 1) | 48% | (12 / 25) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "selector-no-attribute"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected attribute selector",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
const selector = rule.selector
if (!isStandardSyntaxSelector(selector)) {
return
}
parseSelector(selector, result, rule, selectorAST => {
selectorAST.walkAttributes(attribute => {
report({
message: messages.rejected,
node: rule,
index: attribute.sourceIndex,
ruleName,
result,
})
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 48% | (12 / 25) | 0% | (0 / 6) | 0% | (0 / 1) | 48% | (12 / 25) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "selector-no-combinator"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected combinator",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
const selector = rule.selector
if (!isStandardSyntaxSelector(selector)) {
return
}
parseSelector(selector, result, rule, selectorAST => {
selectorAST.walkCombinators(combinator => {
report({
message: messages.rejected,
node: rule,
index: combinator.sourceIndex,
ruleName,
result,
})
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 42.86% | (9 / 21) | 0% | (0 / 4) | 0% | (0 / 1) | 42.86% | (9 / 21) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 1 1 1 1 1 1 1 1 1 | "use strict"
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "selector-no-empty"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected empty selector",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
result.warn((
"'selector-no-empty' has been deprecated and in 8.0 will be removed."
), {
stylelintType: "deprecation",
stylelintReference: "https://stylelint.io/user-guide/rules/selector-no-empty/",
})
root.walkRules(rule => {
let index = 0
rule.selector.split(",").forEach(item => {
index += item.length + 1
if (item.trim() !== "") {
return
}
report({
message: messages.rejected,
node: rule,
index: index - 1,
ruleName,
result,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 43.33% | (13 / 30) | 0% | (0 / 10) | 0% | (0 / 1) | 43.33% | (13 / 30) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isKeyframeRule = require("../../utils/isKeyframeRule")
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "selector-no-id"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected id selector",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
if (isKeyframeRule(rule)) {
return
}
const selector = rule.selector
if (!isStandardSyntaxSelector(selector)) {
return
}
parseSelector(selector, result, rule, selectorAST => {
selectorAST.walkIds(idNode => {
if (idNode.parent.parent.type === "pseudo") {
return
}
report({
message: messages.rejected,
node: rule,
index: idNode.sourceIndex,
ruleName,
result,
})
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 32.26% | (20 / 62) | 0% | (0 / 33) | 0% | (0 / 5) | 32.79% | (20 / 61) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isKeyframeRule = require("../../utils/isKeyframeRule")
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const optionsMatches = require("../../utils/optionsMatches")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const resolvedNestedSelector = require("postcss-resolve-nested-selector")
const ruleName = "selector-no-qualifying-type"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected qualifying type selector",
})
const selectorCharacters = [
"#",
".",
"[",
]
function isSelectorCharacters(value) {
return selectorCharacters.some(char => value.indexOf(char) !== -1)
}
function getRightNodes(node) {
const result = []
let rightNode = node
while ((rightNode = rightNode.next())) {
if (rightNode.type === "combinator") {
break
}
if (rightNode.type !== "id" && rightNode.type !== "class" && rightNode.type !== "attribute") {
continue
}
result.push(rightNode)
}
return result
}
const rule = function (enabled, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: enabled,
possible: [
true,
false,
],
}, {
actual: options,
possible: {
ignore: [
"attribute",
"class",
"id",
],
},
optional: true,
})
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
if (isKeyframeRule(rule)) {
return
}
// Increasing performance
if (!isStandardSyntaxSelector(rule.selector)) {
return
}
if (!isSelectorCharacters(rule.selector)) {
return
}
function checkSelector(selectorAST) {
selectorAST.walkTags(selector => {
const selectorParent = selector.parent
if (selectorParent.nodes.length === 1) {
return
}
const selectorNodes = getRightNodes(selector)
const index = selector.sourceIndex
selectorNodes.forEach(selectorNode => {
if (selectorNode.type === "id" && !optionsMatches(options, "ignore", "id")) {
complain(index)
}
if (selectorNode.type === "class" && !optionsMatches(options, "ignore", "class")) {
complain(index)
}
if (selectorNode.type === "attribute" && !optionsMatches(options, "ignore", "attribute")) {
complain(index)
}
})
})
}
resolvedNestedSelector(rule.selector, rule).forEach(resolvedSelector => {
if (!isStandardSyntaxSelector(resolvedSelector)) {
return
}
parseSelector(resolvedSelector, result, rule, checkSelector)
})
function complain(index) {
report({
ruleName,
result,
node: rule,
message: messages.rejected,
index,
})
}
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 34.43% | (21 / 61) | 0% | (0 / 32) | 0% | (0 / 5) | 35.59% | (21 / 59) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const isKeyframeSelector = require("../../utils/isKeyframeSelector")
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const isStandardSyntaxTypeSelector = require("../../utils/isStandardSyntaxTypeSelector")
const optionsMatches = require("../../utils/optionsMatches")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const resolveNestedSelector = require("postcss-resolve-nested-selector")
const ruleName = "selector-no-type"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected type selector",
})
const rule = function (on, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual: on }, {
actual: options,
possible: {
ignore: [
"descendant",
"compounded",
],
ignoreTypes: [_.isString],
},
optional: true,
})
if (!validOptions) {
return
}
const ignoreDescendant = optionsMatches(options, "ignore", "descendant")
const ignoreCompounded = optionsMatches(options, "ignore", "compounded")
root.walkRules(rule => {
const selector = rule.selector,
selectors = rule.selectors
if (!isStandardSyntaxRule(rule)) {
return
}
if (!isStandardSyntaxSelector(selector)) {
return
}
if (selectors.some(s => isKeyframeSelector(s))) {
return
}
if (ignoreDescendant) {
// Resolve each selector within the list before checking
selectors.forEach(selector => {
resolveNestedSelector(selector, rule).forEach(selector => {
checkSelector(selector, rule)
})
})
} else {
checkSelector(selector, rule)
}
})
function checkSelector(selector, rule) {
parseSelector(selector, result, rule, selectorAST => {
selectorAST.walkTags(tag => {
if (!isStandardSyntaxTypeSelector(tag)) {
return
}
if (optionsMatches(options, "ignoreTypes", tag.value)) {
return
}
if (ignoreDescendant && hasCombinatorBefore(tag)) {
return
}
if (ignoreCompounded && isCompounded(tag)) {
return
}
report({
message: messages.rejected,
node: rule,
index: tag.sourceIndex,
ruleName,
result,
})
})
})
}
}
}
function hasCombinatorBefore(node) {
return node.parent.nodes.slice(0, node.parent.nodes.indexOf(node)).some(isCombinator)
}
function isCompounded(node) {
if (node.prev() && !isCombinator(node.prev())) {
return true
}
if (node.next() && !isCombinator(node.next())) {
return true
}
return false
}
function isCombinator(node) {
if (!node) return false
return _.get(node, "type") === "combinator"
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 48% | (12 / 25) | 0% | (0 / 6) | 0% | (0 / 1) | 48% | (12 / 25) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "selector-no-universal"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected universal selector",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
const selector = rule.selector
if (!isStandardSyntaxSelector(selector)) {
return
}
parseSelector(selector, result, rule, selectorAST => {
selectorAST.walkUniversals(universal => {
report({
message: messages.rejected,
node: rule,
index: universal.sourceIndex,
ruleName,
result,
})
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 46.43% | (13 / 28) | 0% | (0 / 10) | 0% | (0 / 1) | 46.43% | (13 / 28) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isAutoprefixable = require("../../utils/isAutoprefixable")
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "selector-no-vendor-prefix"
const messages = ruleMessages(ruleName, {
rejected: selector => `Unexpected vendor-prefix "${selector}"`,
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
const selector = rule.selector
if (!isStandardSyntaxSelector(selector)) {
return
}
parseSelector(selector, result, rule, selectorTree => {
selectorTree.walkPseudos(pseudoNode => {
if (isAutoprefixable.selector(pseudoNode.value)) {
report({
result,
ruleName,
message: messages.rejected(pseudoNode.value),
node: rule,
index: (rule.raws.before || "").length + pseudoNode.sourceIndex,
})
}
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 42.86% | (15 / 35) | 0% | (0 / 10) | 0% | (0 / 1) | 42.86% | (15 / 35) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const matchesStringOrRegExp = require("../../utils/matchesStringOrRegExp")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const postcss = require("postcss")
const ruleName = "selector-pseudo-class-blacklist"
const messages = ruleMessages(ruleName, {
rejected: selector => `Unexpected pseudo-class "${selector}"`,
})
const rule = function (blacklist) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: blacklist,
possible: [_.isString],
})
if (!validOptions) {
return
}
root.walkRules(rule => {
const selector = rule.selector
if (!isStandardSyntaxSelector(selector)) {
return
}
if (selector.indexOf(":") === -1) {
return
}
parseSelector(selector, result, rule, selectorTree => {
selectorTree.walkPseudos(pseudoNode => {
const value = pseudoNode.value
// Ignore pseudo-elements
if (value.slice(0, 2) === "::") {
return
}
const name = value.slice(1)
if (!matchesStringOrRegExp(postcss.vendor.unprefixed(name).toLowerCase(), blacklist)) {
return
}
report({
index: pseudoNode.sourceIndex,
message: messages.rejected(name),
node: rule,
result,
ruleName,
})
})
})
})
}
}
rule.primaryOptionArray = true
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 36.11% | (13 / 36) | 0% | (0 / 16) | 0% | (0 / 1) | 36.11% | (13 / 36) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const keywordSets = require("../../reference/keywordSets")
const ruleName = "selector-pseudo-class-case"
const messages = ruleMessages(ruleName, {
expected: (actual, expected) => `Expected "${actual}" to be "${expected}"`,
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"lower",
"upper",
],
})
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
const selector = rule.selector
const startIndexPseudo = selector.indexOf(":")
if (startIndexPseudo === -1) {
return
}
parseSelector(selector, result, rule, selectorTree => {
selectorTree.walkPseudos(pseudoNode => {
const pseudo = pseudoNode.value
if (!isStandardSyntaxSelector(pseudo)) {
return
}
if (pseudo.indexOf("::") !== -1 || keywordSets.levelOneAndTwoPseudoElements.has(pseudo.toLowerCase().slice(1))) {
return
}
const expectedPseudo = expectation === "lower" ? pseudo.toLowerCase() : pseudo.toUpperCase()
if (pseudo === expectedPseudo) {
return
}
report({
message: messages.expected(pseudo, expectedPseudo),
node: rule,
index: pseudoNode.sourceIndex,
ruleName,
result,
})
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 36.17% | (17 / 47) | 0% | (0 / 25) | 0% | (0 / 1) | 36.17% | (17 / 47) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const isCustomSelector = require("../../utils/isCustomSelector")
const optionsMatches = require("../../utils/optionsMatches")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const keywordSets = require("../../reference/keywordSets")
const _ = require("lodash")
const postcss = require("postcss")
const ruleName = "selector-pseudo-class-no-unknown"
const messages = ruleMessages(ruleName, {
rejected: selector => `Unexpected unknown pseudo-class selector "${selector}"`,
})
const rule = function (actual, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual }, {
actual: options,
possible: {
ignorePseudoClasses: [_.isString],
},
optional: true,
})
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
const selector = rule.selector
// Return early before parse if no pseudos for performance
if (selector.indexOf(":") === -1) {
return
}
parseSelector(selector, result, rule, selectorTree => {
selectorTree.walkPseudos(pseudoNode => {
const value = pseudoNode.value
if (!isStandardSyntaxSelector(value)) {
return
}
if (isCustomSelector(value)) {
return
}
// Ignore pseudo-elements
if (value.slice(0, 2) === "::") {
return
}
if (optionsMatches(options, "ignorePseudoClasses", pseudoNode.value.slice(1))) {
return
}
const name = value.slice(1)
if (postcss.vendor.prefix(name)
|| keywordSets.pseudoClasses.has(name.toLowerCase())
|| keywordSets.pseudoElements.has(name.toLowerCase())
) {
return
}
if (pseudoNode.prev()) {
const prevPseudoNodeValue = postcss.vendor.unprefixed(pseudoNode.prev().value.toLowerCase().slice(2))
if (keywordSets.webkitProprietaryPseudoElements.has(prevPseudoNodeValue)
&& keywordSets.webkitProprietaryPseudoClasses.has(name.toLowerCase())
) {
return
}
}
report({
message: messages.rejected(value),
node: rule,
index: pseudoNode.sourceIndex,
ruleName,
result,
})
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 32.56% | (14 / 43) | 0% | (0 / 24) | 0% | (0 / 2) | 32.56% | (14 / 43) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const styleSearch = require("style-search")
const ruleName = "selector-pseudo-class-parentheses-space-inside"
const messages = ruleMessages(ruleName, {
expectedOpening: "Expected single space after \"(\"",
rejectedOpening: "Unexpected whitespace after \"(\"",
expectedClosing: "Expected single space before \")\"",
rejectedClosing: "Unexpected whitespace before \")\"",
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
],
})
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
if (rule.selector.indexOf("(") === -1) {
return
}
parseSelector(rule.selector, result, rule, selectorTree => {
selectorTree.walkPseudos(pseudoNode => {
if (_.get(pseudoNode, "parent.parent.type") === "pseudo") {
return
}
const pseudoSelectorString = pseudoNode.toString()
styleSearch({ source: pseudoSelectorString, target: "(" }, match => {
const nextCharIsSpace = pseudoSelectorString[match.startIndex + 1] === " "
const index = pseudoNode.sourceIndex + match.startIndex + 1
if (nextCharIsSpace && expectation === "never") {
complain(messages.rejectedOpening, index)
}
if (!nextCharIsSpace && expectation === "always") {
complain(messages.expectedOpening, index)
}
})
styleSearch({ source: pseudoSelectorString, target: ")" }, match => {
const prevCharIsSpace = pseudoSelectorString[match.startIndex - 1] === " "
const index = pseudoNode.sourceIndex + match.startIndex - 1
if (prevCharIsSpace && expectation === "never") {
complain(messages.rejectedClosing, index)
}
if (!prevCharIsSpace && expectation === "always") {
complain(messages.expectedClosing, index)
}
})
})
})
function complain(message, index) {
report({
message,
index,
result,
ruleName,
node: rule,
})
}
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 42.86% | (15 / 35) | 0% | (0 / 10) | 0% | (0 / 1) | 42.86% | (15 / 35) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const matchesStringOrRegExp = require("../../utils/matchesStringOrRegExp")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const postcss = require("postcss")
const ruleName = "selector-pseudo-class-whitelist"
const messages = ruleMessages(ruleName, {
rejected: selector => `Unexpected pseudo-class "${selector}"`,
})
const rule = function (whitelist) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: whitelist,
possible: [_.isString],
})
if (!validOptions) {
return
}
root.walkRules(rule => {
const selector = rule.selector
if (!isStandardSyntaxSelector(selector)) {
return
}
if (selector.indexOf(":") === -1) {
return
}
parseSelector(selector, result, rule, selectorTree => {
selectorTree.walkPseudos(pseudoNode => {
const value = pseudoNode.value
// Ignore pseudo-elements
if (value.slice(0, 2) === "::") {
return
}
const name = value.slice(1)
if (matchesStringOrRegExp(postcss.vendor.unprefixed(name).toLowerCase(), whitelist)) {
return
}
report({
index: pseudoNode.sourceIndex,
message: messages.rejected(name),
node: rule,
result,
ruleName,
})
})
})
})
}
}
rule.primaryOptionArray = true
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 36.11% | (13 / 36) | 0% | (0 / 16) | 0% | (0 / 1) | 36.11% | (13 / 36) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const keywordSets = require("../../reference/keywordSets")
const ruleName = "selector-pseudo-element-case"
const messages = ruleMessages(ruleName, {
expected: (actual, expected) => `Expected "${actual}" to be "${expected}"`,
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"lower",
"upper",
],
})
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
const selector = rule.selector
const startIndexPseudoElement = selector.indexOf(":")
if (startIndexPseudoElement === -1) {
return
}
parseSelector(selector, result, rule, selectorTree => {
selectorTree.walkPseudos(pseudoNode => {
const pseudoElement = pseudoNode.value
if (!isStandardSyntaxSelector(pseudoElement)) {
return
}
if (pseudoElement.indexOf("::") === -1 && !keywordSets.levelOneAndTwoPseudoElements.has(pseudoElement.toLowerCase().slice(1))) {
return
}
const expectedPseudoElement = expectation === "lower" ? pseudoElement.toLowerCase() : pseudoElement.toUpperCase()
if (pseudoElement === expectedPseudoElement) {
return
}
report({
message: messages.expected(pseudoElement, expectedPseudoElement),
node: rule,
index: pseudoNode.sourceIndex,
ruleName,
result,
})
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 39.39% | (13 / 33) | 0% | (0 / 14) | 0% | (0 / 1) | 40.63% | (13 / 32) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const keywordSets = require("../../reference/keywordSets")
const styleSearch = require("style-search")
const ruleName = "selector-pseudo-element-colon-notation"
const messages = ruleMessages(ruleName, {
expected: q => `Expected ${q} colon pseudo-element notation`,
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"single",
"double",
],
})
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
const selector = rule.selector
// get out early if no pseudo elements or classes
if (selector.indexOf(":") === -1) {
return
}
// match only level 1 and 2 pseudo elements
const pseudoElementsWithColons = _.toArray(keywordSets.levelOneAndTwoPseudoElements).map(x => `:${x}`)
styleSearch({ source: selector.toLowerCase(), target: pseudoElementsWithColons }, match => {
const prevCharIsColon = selector[match.startIndex - 1] === ":"
if (expectation === "single" && !prevCharIsColon) {
return
}
if (expectation === "double" && prevCharIsColon) {
return
}
report({
message: messages.expected(expectation),
node: rule,
index: match.startIndex,
result,
ruleName,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 40% | (16 / 40) | 0% | (0 / 16) | 0% | (0 / 1) | 40% | (16 / 40) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const optionsMatches = require("../../utils/optionsMatches")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const keywordSets = require("../../reference/keywordSets")
const postcss = require("postcss")
const ruleName = "selector-pseudo-element-no-unknown"
const messages = ruleMessages(ruleName, {
rejected: selector => `Unexpected unknown pseudo-element selector "${selector}"`,
})
const rule = function (actual, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual }, {
actual: options,
possible: {
ignorePseudoElements: [_.isString],
},
optional: true,
})
if (!validOptions) {
return
}
root.walkRules(rule => {
if (!isStandardSyntaxRule(rule)) {
return
}
const selector = rule.selector
// Return early before parse if no pseudos for performance
if (selector.indexOf(":") === -1) {
return
}
parseSelector(selector, result, rule, selectorTree => {
selectorTree.walkPseudos(pseudoNode => {
const value = pseudoNode.value
if (!isStandardSyntaxSelector(value)) {
return
}
// Ignore pseudo-classes
if (value.slice(0, 2) !== "::") {
return
}
if (optionsMatches(options, "ignorePseudoElements", pseudoNode.value.slice(2))) {
return
}
const name = value.slice(2)
if (postcss.vendor.prefix(name) || keywordSets.pseudoElements.has(name.toLowerCase())) {
return
}
report({
message: messages.rejected(value),
node: rule,
index: pseudoNode.sourceIndex,
ruleName,
result,
})
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 50% | (9 / 18) | 0% | (0 / 6) | 0% | (0 / 1) | 50% | (9 / 18) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 1 1 1 1 1 1 1 1 1 | "use strict"
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "selector-root-no-composition"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected composition",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
result.warn((
`'${ruleName}' has been deprecated and in 8.0 will be removed. Instead use the community 'stylelint-suitcss' plugin pack.`
), {
stylelintType: "deprecation",
stylelintReference: `https://stylelint.io/user-guide/rules/${ruleName}/`,
})
root.walkRules(rule => {
if (rule.selector.toLowerCase().indexOf(":root") === -1 || rule.selector.toLowerCase().trim() === ":root") {
return
}
report({
message: messages.rejected,
node: rule,
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 37.84% | (14 / 37) | 0% | (0 / 14) | 0% | (0 / 1) | 38.89% | (14 / 36) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isKeyframeSelector = require("../../utils/isKeyframeSelector")
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const isStandardSyntaxTypeSelector = require("../../utils/isStandardSyntaxTypeSelector")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "selector-type-case"
const messages = ruleMessages(ruleName, {
expected: (actual, expected) => `Expected "${actual}" to be "${expected}"`,
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"lower",
"upper",
],
})
if (!validOptions) {
return
}
root.walkRules(rule => {
const selector = rule.selector,
selectors = rule.selectors
if (!isStandardSyntaxRule(rule)) {
return
}
if (!isStandardSyntaxSelector(selector)) {
return
}
if (selectors.some(s => isKeyframeSelector(s))) {
return
}
parseSelector(selector, result, rule, selectorAST => {
selectorAST.walkTags(tag => {
if (!isStandardSyntaxTypeSelector(tag)) {
return
}
const sourceIndex = tag.sourceIndex,
value = tag.value
const expectedValue = expectation === "lower" ? value.toLowerCase() : value.toUpperCase()
if (value === expectedValue) {
return
}
report({
message: messages.expected(value, expectedValue),
node: rule,
index: sourceIndex,
ruleName,
result,
})
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 39.58% | (19 / 48) | 0% | (0 / 23) | 0% | (0 / 1) | 40.43% | (19 / 47) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isKeyframeSelector = require("../../utils/isKeyframeSelector")
const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule")
const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector")
const isStandardSyntaxTypeSelector = require("../../utils/isStandardSyntaxTypeSelector")
const optionsMatches = require("../../utils/optionsMatches")
const parseSelector = require("../../utils/parseSelector")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const htmlTags = require("html-tags")
const _ = require("lodash")
const svgTags = require("svg-tags")
const ruleName = "selector-type-no-unknown"
const messages = ruleMessages(ruleName, {
rejected: selector => `Unexpected unknown type selector "${selector}"`,
})
// htmlTags includes only "standard" tags. So we augment it with older tags etc.
const nonStandardHtmlTags = new Set([
"acronym",
"applet",
"basefont",
"big",
"blink",
"center",
"content",
"dir",
"font",
"frame",
"frameset",
"hgroup",
"isindex",
"keygen",
"listing",
"marquee",
"noembed",
"plaintext",
"spacer",
"strike",
"tt",
"xmp",
])
const rule = function (actual, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual }, {
actual: options,
possible: {
ignore: [
"default-namespace",
],
ignoreNamespaces: [_.isString],
ignoreTypes: [_.isString],
},
optional: true,
})
if (!validOptions) {
return
}
root.walkRules(rule => {
const selector = rule.selector,
selectors = rule.selectors
if (!isStandardSyntaxRule(rule)) {
return
}
if (!isStandardSyntaxSelector(selector)) {
return
}
if (selectors.some(s => isKeyframeSelector(s))) {
return
}
parseSelector(selector, result, rule, selectorTree => {
selectorTree.walkTags(tagNode => {
if (!isStandardSyntaxTypeSelector(tagNode)) {
return
}
if (
optionsMatches(options, "ignore", "default-namespace")
&& !tagNode.hasOwnProperty("namespace")
) {
return
}
if (optionsMatches(options, "ignoreNamespaces", tagNode.namespace)) {
return
}
if (optionsMatches(options, "ignoreTypes", tagNode.value)) {
return
}
const tagName = tagNode.value
const tagNameLowerCase = tagName.toLowerCase()
if (htmlTags.indexOf(tagNameLowerCase) !== -1 || svgTags.indexOf(tagNameLowerCase) !== -1 || nonStandardHtmlTags.has(tagNameLowerCase)) {
return
}
report({
message: messages.rejected(tagName),
node: rule,
index: tagNode.sourceIndex,
ruleName,
result,
})
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 32.35% | (22 / 68) | 0% | (0 / 49) | 0% | (0 / 6) | 32.84% | (22 / 67) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isStandardSyntaxDeclaration = require("../../utils/isStandardSyntaxDeclaration")
const isStandardSyntaxProperty = require("../../utils/isStandardSyntaxProperty")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const shorthandData = require("../../reference/shorthandData")
const valueParser = require("postcss-value-parser")
const postcss = require("postcss")
const ruleName = "shorthand-property-no-redundant-values"
const messages = ruleMessages(ruleName, {
rejected: (unexpected, expected) => `Unexpected longhand value '${unexpected}' instead of '${expected}'`,
})
const shorthandableProperties = new Set(Object.keys(shorthandData))
const ignoredCharacters = [
"+",
"-",
"*",
"/",
"(",
")",
"$",
"@",
"--",
"var(",
]
const ignoredShorthandProperties = new Set([
"background",
"font",
"border",
"border-top",
"border-bottom",
"border-left",
"border-right",
"list-style",
"transition",
])
function isIgnoredCharacters(value) {
return ignoredCharacters.some(char => value.indexOf(char) !== -1)
}
function canCondense(top, right) {
const bottom = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null
const left = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null
const lowerTop = top.toLowerCase()
const lowerRight = right.toLowerCase()
const lowerBottom = bottom && bottom.toLowerCase()
const lowerLeft = left && left.toLowerCase()
if (canCondenseToOneValue(lowerTop, lowerRight, lowerBottom, lowerLeft)) {
return [top]
} else if (canCondenseToTwoValues(lowerTop, lowerRight, lowerBottom, lowerLeft)) {
return [
top,
right,
]
} else if (canCondenseToThreeValues(lowerTop, lowerRight, lowerBottom, lowerLeft)) {
return [
top,
right,
bottom,
]
} else {
return [
top,
right,
bottom,
left,
]
}
}
function canCondenseToOneValue(top, right, bottom, left) {
if (top !== right) {
return false
}
return top === bottom && (bottom === left || !left) || !bottom && !left
}
function canCondenseToTwoValues(top, right, bottom, left) {
return top === bottom && right === left || top === bottom && !left && top !== right
}
function canCondenseToThreeValues(top, right, bottom, left) {
return right === left
}
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkDecls(decl => {
if (!isStandardSyntaxDeclaration(decl) || !isStandardSyntaxProperty(decl.prop)) {
return
}
const prop = decl.prop,
value = decl.value
const normalizedProp = postcss.vendor.unprefixed(prop.toLowerCase())
// Ignore not shorthandable properties, and math operations
if (isIgnoredCharacters(value) || !shorthandableProperties.has(normalizedProp) || ignoredShorthandProperties.has(normalizedProp)) {
return
}
const valuesToShorthand = []
valueParser(value).walk(valueNode => {
if (valueNode.type !== "word") {
return
}
valuesToShorthand.push(valueParser.stringify(valueNode))
})
if (valuesToShorthand.length <= 1 || valuesToShorthand.length > 4) {
return
}
const shortestForm = canCondense.apply(undefined, valuesToShorthand)
const shortestFormString = shortestForm.filter(value => {
return value
}).join(" ")
const valuesFormString = valuesToShorthand.join(" ")
if (shortestFormString.toLowerCase() === valuesFormString.toLowerCase()) {
return
}
report({
message: messages.rejected(value, shortestFormString),
node: decl,
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 43.48% | (10 / 23) | 0% | (0 / 6) | 0% | (0 / 1) | 45.45% | (10 / 22) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const styleSearch = require("style-search")
const ruleName = "string-no-newline"
const messages = ruleMessages(ruleName, {
rejected: "Unexpected newline in string",
})
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
const cssString = root.toString()
styleSearch({
source: cssString,
target: "\n",
strings: "only",
}, match => {
const charBefore = cssString[match.startIndex - 1]
let index = match.startIndex
if (charBefore === "\\") {
return
}
if (charBefore === "\r") index -= 1
report({
message: messages.rejected,
node: root,
index,
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 52.63% | (10 / 19) | 0% | (0 / 4) | 0% | (0 / 1) | 52.63% | (10 / 19) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const styleSearch = require("style-search")
const ruleName = "string-quotes"
const messages = ruleMessages(ruleName, {
expected: q => `Expected ${q} quotes`,
})
const rule = function (expectation) {
const erroneousQuote = expectation === "single" ? "\"" : "'"
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"single",
"double",
],
})
if (!validOptions) {
return
}
const cssString = root.toString()
styleSearch({ source: cssString, target: erroneousQuote }, match => {
report({
message: messages.expected(expectation),
node: root,
index: match.startIndex,
result,
ruleName,
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 29.27% | (12 / 41) | 0% | (0 / 28) | 0% | (0 / 4) | 29.27% | (12 / 41) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const ruleName = "stylelint-disable-reason"
const messages = ruleMessages(ruleName, {
expectedBefore: "Expected comment reason before `stylelint-disable` comment",
expectedAfter: "Expected comment reason after `stylelint-disable` comment",
})
const stylelintDisableCommand = "stylelint-disable"
const stylelintDisableLineCommand = "stylelint-disable-line"
const rule = function (expectation) {
return function (root, result) {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always-before",
"always-after",
],
})
if (!validOptions) {
return
}
result.warn((
`'${ruleName}' has been deprecated and in 8.0 will be removed.`
), {
stylelintType: "deprecation",
stylelintReference: `https://stylelint.io/user-guide/rules/${ruleName}/`,
})
root.walkComments(function (comment) {
if (comment.text.indexOf(stylelintDisableCommand) !== 0) {
return
}
if (expectation === "always-before") {
const prev = comment.prev()
const prevIsCommentAndValid = prev && prev.type === "comment" && !isDisableCommand(prev.text)
let prevDisableLineIsCommentAndValid = false
if (comment.text.indexOf(stylelintDisableLineCommand) === 0 && !prevIsCommentAndValid && prev) {
const friendlyPrev = prev.prev()
prevDisableLineIsCommentAndValid = friendlyPrev && friendlyPrev.type === "comment" && !isDisableCommand(friendlyPrev.text)
}
if (!prevIsCommentAndValid && !prevDisableLineIsCommentAndValid) {
const disabledRanges = result.stylelint.disabledRanges
result.stylelint.disabledRanges = false
report({
message: messages.expectedBefore,
node: comment,
result,
ruleName,
})
result.stylelint.disabledRanges = disabledRanges
}
} else if (expectation === "always-after") {
const next = comment.next()
const nextIsCommentAndValid = next && next.type === "comment" && !isDisableCommand(next.text)
if (!nextIsCommentAndValid) {
const disabledRanges = result.stylelint.disabledRanges
result.stylelint.disabledRanges = false
report({
message: messages.expectedAfter,
node: comment,
result,
ruleName,
})
result.stylelint.disabledRanges = disabledRanges
}
}
})
function isDisableCommand(text) {
return text.indexOf(stylelintDisableCommand) === 0
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 38.1% | (16 / 42) | 0% | (0 / 24) | 0% | (0 / 3) | 39.02% | (16 / 41) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const declarationValueIndex = require("../../utils/declarationValueIndex")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const keywordSets = require("../../reference/keywordSets")
const postcss = require("postcss")
const valueParser = require("postcss-value-parser")
const ruleName = "time-min-milliseconds"
const messages = ruleMessages(ruleName, {
expected: time => `Expected a minimum of ${time} milliseconds`,
})
const rule = function (minimum) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: minimum,
possible: _.isNumber,
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const propertyName = postcss.vendor.unprefixed(decl.prop.toLowerCase())
if (
keywordSets.longhandTimeProperties.has(propertyName)
&& !isAcceptableTime(decl.value)
) {
complain(decl)
}
if (keywordSets.shorthandTimeProperties.has(propertyName)) {
const valueList = postcss.list.space(decl.value)
for (const value of valueList) {
if (!isAcceptableTime(value)) {
complain(decl, decl.value.indexOf(value))
}
}
}
})
function isAcceptableTime(time) {
const parsedTime = valueParser.unit(time)
if (!parsedTime) return true
if (parsedTime.number <= 0) {
return true
}
if (parsedTime.unit.toLowerCase() === "ms" && parsedTime.number < minimum) {
return false
}
if (parsedTime.unit.toLowerCase() === "s" && parsedTime.number * 1000 < minimum) {
return false
}
return true
}
function complain(decl, offset) {
offset = offset || 0
report({
result,
ruleName,
message: messages.expected(minimum),
index: declarationValueIndex(decl) + offset,
node: decl,
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 38.1% | (16 / 42) | 0% | (0 / 24) | 0% | (0 / 3) | 39.02% | (16 / 41) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const declarationValueIndex = require("../../utils/declarationValueIndex")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const keywordSets = require("../../reference/keywordSets")
const postcss = require("postcss")
const valueParser = require("postcss-value-parser")
const ruleName = "time-no-imperceptible"
const messages = ruleMessages(ruleName, {
rejected: time => `Unexpected time value "${time}" less than or equal to 100ms`,
})
const MINIMUM_MILLISECONDS = 100
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
result.warn((
`'${ruleName}' has been deprecated and in 8.0 will be removed. Instead use 'time-min-milliseconds' with '100' as its primary option.`
), {
stylelintType: "deprecation",
stylelintReference: `https://stylelint.io/user-guide/rules/${ruleName}/`,
})
root.walkDecls(decl => {
if (keywordSets.longhandTimeProperties.has(postcss.vendor.unprefixed(decl.prop.toLowerCase()))) {
if (isImperceptibleTime(decl.value)) {
complain(messages.rejected(decl.value), decl)
}
}
if (keywordSets.shorthandTimeProperties.has(postcss.vendor.unprefixed(decl.prop.toLowerCase()))) {
const valueList = postcss.list.space(decl.value)
for (const value of valueList) {
if (isImperceptibleTime(value)) {
complain(messages.rejected(value), decl, decl.value.indexOf(value))
}
}
}
})
function isImperceptibleTime(time) {
const parsedTime = valueParser.unit(time)
if (!parsedTime) return false
const absoluteTime = Math.abs(parsedTime.number)
if (parsedTime.unit.toLowerCase() === "ms" && absoluteTime <= MINIMUM_MILLISECONDS) {
return true
}
if (parsedTime.unit.toLowerCase() === "s" && absoluteTime * 1000 <= MINIMUM_MILLISECONDS) {
return true
}
return false
}
function complain(message, decl) {
const offset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0
report({
result,
ruleName,
message,
index: declarationValueIndex(decl) + offset,
node: decl,
})
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 48.65% | (18 / 37) | 0% | (0 / 15) | 0% | (0 / 3) | 51.43% | (18 / 35) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../../utils/atRuleParamIndex")
const declarationValueIndex = require("../../utils/declarationValueIndex")
const getUnitFromValueNode = require("../../utils/getUnitFromValueNode")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const validateObjectWithStringArrayProps = require("../../utils/validateObjectWithStringArrayProps")
const valueParser = require("postcss-value-parser")
const ruleName = "unit-blacklist"
const messages = ruleMessages(ruleName, {
rejected: unit => `Unexpected unit "${unit}"`,
})
const rule = function (blacklistInput, options) {
const blacklist = [].concat(blacklistInput)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: blacklist,
possible: [_.isString],
}, {
optional: true,
actual: options,
possible: {
ignoreProperties: validateObjectWithStringArrayProps,
},
})
if (!validOptions) {
return
}
function check(node, value, getIndex) {
valueParser(value).walk(function (valueNode) {
// Ignore wrong units within `url` function
if (valueNode.type === "function" && valueNode.value.toLowerCase() === "url") {
return false
}
const unit = getUnitFromValueNode(valueNode)
if (!unit || unit && blacklist.indexOf(unit.toLowerCase()) === -1) {
return
}
if (options && optionsMatches(options.ignoreProperties, unit.toLowerCase(), node.prop)) {
return
}
report({
index: getIndex(node) + valueNode.sourceIndex,
message: messages.rejected(unit),
node,
result,
ruleName,
})
})
}
root.walkAtRules(/^media$/i, atRule => check(atRule, atRule.params, atRuleParamIndex))
root.walkDecls(decl => check(decl, decl.value, declarationValueIndex))
}
}
rule.primaryOptionArray = true
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 42.42% | (14 / 33) | 0% | (0 / 12) | 0% | (0 / 2) | 45.16% | (14 / 31) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../../utils/atRuleParamIndex")
const declarationValueIndex = require("../../utils/declarationValueIndex")
const getUnitFromValueNode = require("../../utils/getUnitFromValueNode")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const valueParser = require("postcss-value-parser")
const ruleName = "unit-case"
const messages = ruleMessages(ruleName, {
expected: (actual, expected) => `Expected "${actual}" to be "${expected}"`,
})
const rule = function (expectation) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"lower",
"upper",
],
})
if (!validOptions) {
return
}
function check(node, value, getIndex) {
valueParser(value).walk(valueNode => {
// Ignore wrong units within `url` function
if (valueNode.type === "function" && valueNode.value.toLowerCase() === "url") {
return false
}
const unit = getUnitFromValueNode(valueNode)
if (!unit) {
return
}
const expectedUnit = expectation === "lower" ? unit.toLowerCase() : unit.toUpperCase()
if (unit === expectedUnit) {
return
}
report({
index: getIndex(node) + valueNode.sourceIndex,
message: messages.expected(unit, expectedUnit),
node,
result,
ruleName,
})
})
}
root.walkAtRules(/^media$/i, atRule => check(atRule, atRule.params, atRuleParamIndex))
root.walkDecls(decl => check(decl, decl.value, declarationValueIndex))
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 45.95% | (17 / 37) | 0% | (0 / 12) | 0% | (0 / 3) | 48.57% | (17 / 35) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../../utils/atRuleParamIndex")
const declarationValueIndex = require("../../utils/declarationValueIndex")
const getUnitFromValueNode = require("../../utils/getUnitFromValueNode")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const keywordSets = require("../../reference/keywordSets")
const valueParser = require("postcss-value-parser")
const ruleName = "unit-no-unknown"
const messages = ruleMessages(ruleName, {
rejected: unit => `Unexpected unknown unit "${unit}"`,
})
const rule = function (actual, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual }, {
actual: options,
possible: {
ignoreUnits: [_.isString],
},
optional: true,
})
if (!validOptions) {
return
}
function check(node, value, getIndex) {
valueParser(value).walk(function (valueNode) {
// Ignore wrong units within `url` function
if (valueNode.type === "function" && valueNode.value.toLowerCase() === "url") {
return false
}
const unit = getUnitFromValueNode(valueNode)
if (!unit) {
return
}
if (optionsMatches(options, "ignoreUnits", unit)) {
return
}
if (keywordSets.units.has(unit.toLowerCase())) {
return
}
report({
index: getIndex(node) + valueNode.sourceIndex,
message: messages.rejected(unit),
node,
result,
ruleName,
})
})
}
root.walkAtRules(/^media$/i, atRule => check(atRule, atRule.params, atRuleParamIndex))
root.walkDecls(decl => check(decl, decl.value, declarationValueIndex))
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 48.65% | (18 / 37) | 0% | (0 / 15) | 0% | (0 / 3) | 51.43% | (18 / 35) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const atRuleParamIndex = require("../../utils/atRuleParamIndex")
const declarationValueIndex = require("../../utils/declarationValueIndex")
const getUnitFromValueNode = require("../../utils/getUnitFromValueNode")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const validateObjectWithStringArrayProps = require("../../utils/validateObjectWithStringArrayProps")
const valueParser = require("postcss-value-parser")
const ruleName = "unit-whitelist"
const messages = ruleMessages(ruleName, {
rejected: unit => `Unexpected unit "${unit}"`,
})
const rule = function (whitelistInput, options) {
const whitelist = [].concat(whitelistInput)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: whitelist,
possible: [_.isString],
}, {
optional: true,
actual: options,
possible: {
ignoreProperties: validateObjectWithStringArrayProps,
},
})
if (!validOptions) {
return
}
function check(node, value, getIndex) {
valueParser(value).walk(function (valueNode) {
// Ignore wrong units within `url` function
if (valueNode.type === "function" && valueNode.value.toLowerCase() === "url") {
return false
}
const unit = getUnitFromValueNode(valueNode)
if (!unit || unit && whitelist.indexOf(unit.toLowerCase()) !== -1) {
return
}
if (options && optionsMatches(options["ignoreProperties"], unit.toLowerCase(), node.prop)) {
return
}
report({
index: getIndex(node) + valueNode.sourceIndex,
message: messages.rejected(unit),
node,
result,
ruleName,
})
})
}
root.walkAtRules(/^media$/i, atRule => check(atRule, atRule.params, atRuleParamIndex))
root.walkDecls(decl => check(decl, decl.value, declarationValueIndex))
}
}
rule.primaryOptionArray = true
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 30.14% | (22 / 73) | 0% | (0 / 81) | 0% | (0 / 1) | 30.14% | (22 / 73) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1 1 1 1 | "use strict"
const keywordSets = require("../../reference/keywordSets")
const declarationValueIndex = require("../../utils/declarationValueIndex")
const getUnitFromValueNode = require("../../utils/getUnitFromValueNode")
const isCounterIncrementCustomIdentValue = require("../../utils/isCounterIncrementCustomIdentValue")
const isCounterResetCustomIdentValue = require("../../utils/isCounterResetCustomIdentValue")
const isStandardSyntaxValue = require("../../utils/isStandardSyntaxValue")
const matchesStringOrRegExp = require("../../utils/matchesStringOrRegExp")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const valueParser = require("postcss-value-parser")
const ruleName = "value-keyword-case"
const messages = ruleMessages(ruleName, {
expected: (actual, expected) => `Expected "${actual}" to be "${expected}"`,
})
// Operators are interpreted as "words" by the value parser, so we want to make sure to ignore them.
const ignoredCharacters = new Set([
"+",
"-",
"/",
"*",
"%",
])
const mapLowercaseKeywordsToCamelCase = new Map()
keywordSets.camelCaseKeywords.forEach(func => {
mapLowercaseKeywordsToCamelCase.set(func.toLowerCase(), func)
})
const rule = function (expectation, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"lower",
"upper",
],
}, {
actual: options,
possible: {
ignoreKeywords: [_.isString],
},
optional: true,
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const prop = decl.prop,
value = decl.value
valueParser(value).walk(node => {
const valueLowerCase = node.value.toLowerCase()
// Ignore system colors
if (keywordSets.systemColors.has(valueLowerCase)) {
return
}
// Ignore keywords within `url` and `var` function
if (node.type === "function" && (valueLowerCase === "url" || valueLowerCase === "var" || valueLowerCase === "counter" || valueLowerCase === "counters" || valueLowerCase === "attr")) {
return false
}
const keyword = node.value
// Ignore css variables, and hex values, and math operators, and sass interpolation
if (node.type !== "word" || !isStandardSyntaxValue(node.value) || value.indexOf("#") !== -1 || ignoredCharacters.has(keyword) || getUnitFromValueNode(node)) {
return
}
if (prop === "animation" && !keywordSets.animationShorthandKeywords.has(valueLowerCase) && !keywordSets.animationNameKeywords.has(valueLowerCase)) {
return
}
if (prop === "animation-name" && !keywordSets.animationNameKeywords.has(valueLowerCase)) {
return
}
if (prop === "font" && !keywordSets.fontShorthandKeywords.has(valueLowerCase) && !keywordSets.fontFamilyKeywords.has(valueLowerCase)) {
return
}
if (prop === "font-family" && !keywordSets.fontFamilyKeywords.has(valueLowerCase)) {
return
}
if (prop === "counter-increment" && isCounterIncrementCustomIdentValue(valueLowerCase)) {
return
}
if (prop === "counter-reset" && isCounterResetCustomIdentValue(valueLowerCase)) {
return
}
if (prop === "grid-row" && !keywordSets.gridRowKeywords.has(valueLowerCase)) {
return
}
if (prop === "grid-column" && !keywordSets.gridColumnKeywords.has(valueLowerCase)) {
return
}
if (prop === "grid-area" && !keywordSets.gridAreaKeywords.has(valueLowerCase)) {
return
}
if (prop === "list-style" && !keywordSets.listStyleShorthandKeywords.has(valueLowerCase) && !keywordSets.listStyleTypeKeywords.has(valueLowerCase)) {
return
}
if (prop === "list-style-type" && !keywordSets.listStyleTypeKeywords.has(valueLowerCase)) {
return
}
const ignoreKeywords = options && options.ignoreKeywords || []
if (ignoreKeywords.length > 0 && matchesStringOrRegExp(keyword, ignoreKeywords)) {
return
}
const keywordLowerCase = keyword.toLocaleLowerCase()
let expectedKeyword = null
if (expectation === "lower" && mapLowercaseKeywordsToCamelCase.has(keywordLowerCase)) {
expectedKeyword = mapLowercaseKeywordsToCamelCase.get(keywordLowerCase)
} else if (expectation === "lower") {
expectedKeyword = keyword.toLowerCase()
} else {
expectedKeyword = keyword.toUpperCase()
}
if (keyword === expectedKeyword) {
return
}
report({
message: messages.expected(keyword, expectedKeyword),
node: decl,
index: declarationValueIndex(decl) + node.sourceIndex,
result,
ruleName,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 52.63% | (10 / 19) | 0% | (0 / 2) | 0% | (0 / 1) | 52.63% | (10 / 19) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const valueListCommaWhitespaceChecker = require("../valueListCommaWhitespaceChecker")
const ruleName = "value-list-comma-newline-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected newline after \",\"",
expectedAfterMultiLine: () => "Expected newline after \",\" in a multi-line list",
rejectedAfterMultiLine: () => "Unexpected whitespace after \",\" in a multi-line list",
})
const rule = function (expectation) {
const checker = whitespaceChecker("newline", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"always-multi-line",
"never-multi-line",
],
})
if (!validOptions) {
return
}
valueListCommaWhitespaceChecker({
root,
result,
locationChecker: checker.afterOneOnly,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 52.63% | (10 / 19) | 0% | (0 / 2) | 0% | (0 / 1) | 52.63% | (10 / 19) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const valueListCommaWhitespaceChecker = require("../valueListCommaWhitespaceChecker")
const ruleName = "value-list-comma-newline-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected newline before \",\"",
expectedBeforeMultiLine: () => "Expected newline before \",\" in a multi-line list",
rejectedBeforeMultiLine: () => "Unexpected whitespace before \",\" in a multi-line list",
})
const rule = function (expectation) {
const checker = whitespaceChecker("newline", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"always-multi-line",
"never-multi-line",
],
})
if (!validOptions) {
return
}
valueListCommaWhitespaceChecker({
root,
result,
locationChecker: checker.beforeAllowingIndentation,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 50% | (10 / 20) | 0% | (0 / 2) | 0% | (0 / 1) | 50% | (10 / 20) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const valueListCommaWhitespaceChecker = require("../valueListCommaWhitespaceChecker")
const ruleName = "value-list-comma-space-after"
const messages = ruleMessages(ruleName, {
expectedAfter: () => "Expected single space after \",\"",
rejectedAfter: () => "Unexpected whitespace after \",\"",
expectedAfterSingleLine: () => "Expected single space after \",\" in a single-line list",
rejectedAfterSingleLine: () => "Unexpected whitespace after \",\" in a single-line list",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-single-line",
"never-single-line",
],
})
if (!validOptions) {
return
}
valueListCommaWhitespaceChecker({
root,
result,
locationChecker: checker.after,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 50% | (10 / 20) | 0% | (0 / 2) | 0% | (0 / 1) | 50% | (10 / 20) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 1 1 1 1 1 1 1 1 1 1 | "use strict"
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const whitespaceChecker = require("../../utils/whitespaceChecker")
const valueListCommaWhitespaceChecker = require("../valueListCommaWhitespaceChecker")
const ruleName = "value-list-comma-space-before"
const messages = ruleMessages(ruleName, {
expectedBefore: () => "Expected single space before \",\"",
rejectedBefore: () => "Unexpected whitespace before \",\"",
expectedBeforeSingleLine: () => "Unexpected whitespace before \",\" in a single-line list",
rejectedBeforeSingleLine: () => "Unexpected whitespace before \",\" in a single-line list",
})
const rule = function (expectation) {
const checker = whitespaceChecker("space", expectation, messages)
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: expectation,
possible: [
"always",
"never",
"always-single-line",
"never-single-line",
],
})
if (!validOptions) {
return
}
valueListCommaWhitespaceChecker({
root,
result,
locationChecker: checker.before,
checkedRuleName: ruleName,
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 40.74% | (11 / 27) | 0% | (0 / 8) | 0% | (0 / 1) | 40.74% | (11 / 27) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const styleSearch = require("style-search")
const ruleName = "value-list-max-empty-lines"
const messages = ruleMessages(ruleName, {
expected: max => `Expected no more than ${max} empty line(s)`,
})
const rule = function (max) {
const maxAdjacentNewlines = max + 1
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: max,
possible: _.isNumber,
})
if (!validOptions) {
return
}
root.walkDecls(decl => {
const value = decl.value
const repeatLFNewLines = _.repeat("\n", maxAdjacentNewlines)
const repeatCRLFNewLines = _.repeat("\r\n", maxAdjacentNewlines)
styleSearch({ source: value, target: "\n" }, match => {
if (value.substr(match.startIndex + 1, maxAdjacentNewlines) === repeatLFNewLines || value.substr(match.startIndex + 1, maxAdjacentNewlines * 2) === repeatCRLFNewLines) {
// Put index at `\r` if it's CRLF, otherwise leave it at `\n`
let index = match.startIndex
if (value[index - 1] === "\r") {
index -= 1
}
report({
message: messages.expected(max),
node: decl,
index,
result,
ruleName,
})
}
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| index.js | 50% | (14 / 28) | 0% | (0 / 11) | 0% | (0 / 1) | 50% | (14 / 28) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const isAutoprefixable = require("../../utils/isAutoprefixable")
const isStandardSyntaxDeclaration = require("../../utils/isStandardSyntaxDeclaration")
const isStandardSyntaxProperty = require("../../utils/isStandardSyntaxProperty")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const styleSearch = require("style-search")
const ruleName = "value-no-vendor-prefix"
const messages = ruleMessages(ruleName, {
rejected: value => `Unexpected vendor-prefix "${value}"`,
})
const valuePrefixes = [
"-webkit-",
"-moz-",
"-ms-",
"-o-",
]
const rule = function (actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual })
if (!validOptions) {
return
}
root.walkDecls(decl => {
if (!isStandardSyntaxDeclaration(decl) || !isStandardSyntaxProperty(decl.prop) || decl.value[0] !== "-") {
return
}
const prop = decl.prop,
value = decl.value
// Search the full declaration in order to get an accurate index
styleSearch({ source: value.toLowerCase(), target: valuePrefixes }, match => {
const fullIdentifier = /^(-[a-z-]+)\b/i.exec(value.slice(match.startIndex))[1]
if (!isAutoprefixable.propertyValue(prop, fullIdentifier)) {
return
}
report({
message: messages.rejected(fullIdentifier),
node: decl,
index: prop.length + (decl.raws.between || "").length + match.startIndex,
result,
ruleName,
})
})
})
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| basicChecks.js | 100% | (1 / 1) | 100% | (0 / 0) | 100% | (0 / 0) | 100% | (1 / 1) | |
| createRuleTester.js | 18.09% | (17 / 94) | 4.26% | (2 / 47) | 0% | (0 / 7) | 18.28% | (17 / 93) | |
| mergeTestDescriptions.js | 30% | (3 / 10) | 0% | (0 / 2) | 0% | (0 / 2) | 33.33% | (3 / 9) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 1 | "use strict"
// These should pass for *almost* every rule
module.exports = [ {
code: "",
description: "empty stylesheet",
}, {
code: "a {}",
description: "empty rule",
}, {
code: "@import \"foo.css\";",
description: "blockless statement",
}, {
code: ":global {}",
description: "CSS Modules global empty rule set",
} ]
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const _ = require("lodash")
const assignDisabledRanges = require("../assignDisabledRanges")
const basicChecks = require("./basicChecks")
const lessSyntax = require("postcss-less")
const normalizeRuleSettings = require("../normalizeRuleSettings")
const postcss = require("postcss")
const scssSyntax = require("postcss-scss")
const sugarss = require("sugarss")
/**
* Create a stylelint rule testing function.
*
* Pass in an `equalityCheck` function. Given some information,
* this checker should use Whatever Test Runner to perform
* equality checks.
*
* `equalityCheck` should accept two arguments:
* - `processCss` {Promise}: A Promise that resolves with an array of
* comparisons that you need to check (documented below).
* - `context` {object}: An object that contains additional information
* you may need:
* - `caseDescription` {string}: A description of the test case as a whole.
* Will look like this:
* > rule: value-list-comma-space-before
* > config: "always-single-line"
* > code: "a { background-size: 0 ,0;\n}"
* - `comparisonCount` {number}: The number of comparisons that
* will need to be performed (e.g. useful for tape).
* - `completeAssertionDescription` {string}: While each individual
* comparison may have its own description, this is a description
* of the whole assertion (e.g. useful for Mocha).
* - `only` {boolean}: If `true`, the test runner should only run this
* test case (e.g. `test.only` in tape, `describe.only` in Mocha).
*
* `processCss` is a Promsie that resolves with an array of comparisons.
* Each comparison has the following properties:
* - `actual` {any}: Some actual value.
* - `expected` {any}: Some expected value.
* - `description` {string}: A (possibly empty) description of the comparison.
*
* Within `equalityCheck`, you need to ensure that you:
* - Set up the test case.
* - When `processCss` resolves, loop through every comparison.
* - For each comparison, make an assertion checking that `actual === expected`.
*
* The `testRule` function that you get has a simple signature:
* `testRule(rule, testGroupDescription)`.
*
* `rule` is just the rule that you are testing (a function).
*
* `testGroupDescription` is an object fitting the following schema.
*
* Required properties:
* - `ruleName` {string}: The name of the rule. Used in descriptions.
* - `config` {any}: The rule's configuration for this test group.
* Should match the format you'd use in `.stylelintrc`.
* - `accept` {array}: An array of objects describing test cases that
* should not violate the rule. Each object has these properties:
* - `code` {string}: The source CSS to check.
* - `description` {[string]}: An optional description of the case.
* - `reject` {array}: An array of objects describing test cases that
* should violate the rule once. Each object has these properties:
* - `code` {string}: The source CSS to check.
* - `message` {string}: The message of the expected violation.
* - `line` {[number]}: The expected line number of the violation.
* If this is left out, the line won't be checked.
* - `column` {[number]}: The expected column number of the violation.
* If this is left out, the column won't be checked.
* - `description` {[string]}: An optional description of the case.
*
* Optional properties:
* - `syntax` {"css"|"scss"|"less"|"sugarss"}: Defaults to `"css"`.
* - `skipBasicChecks` {boolean}: Defaults to `false`. If `true`, a
* few rudimentary checks (that should almost always be included)
* will not be performed.
* - `preceedingPlugins` {array}: An array of PostCSS plugins that
* should be run before the CSS is tested.
*
* @param {function} equalityCheck - Described above
* @return {function} testRule - Decsribed above
*/
let onlyTest
function checkCaseForOnly(caseType, testCase) {
if (!testCase.only) {
return
}
/* istanbul ignore next */
if (onlyTest) {
throw new Error("Cannot use `only` on multiple test cases")
}
onlyTest = { case: testCase, type: caseType }
}
module.exports = function (equalityCheck) {
return function (rule, schema) {
const alreadyHadOnlyTest = !!onlyTest
if (schema.accept) {
schema.accept.forEach(_.partial(checkCaseForOnly, "accept"))
}
if (schema.reject) {
schema.reject.forEach(_.partial(checkCaseForOnly, "reject"))
}
if (onlyTest) {
schema = _.assign(_.omit(schema, [ "accept", "reject" ]), {
skipBasicChecks: true,
[onlyTest.type]: [onlyTest.case],
})
}
if (!alreadyHadOnlyTest) {
process.nextTick(() => {
processGroup(rule, schema, equalityCheck)
})
}
}
}
function processGroup(rule, schema, equalityCheck) {
const ruleName = schema.ruleName
const ruleOptions = normalizeRuleSettings(schema.config, ruleName)
const rulePrimaryOptions = ruleOptions[0]
const ruleSecondaryOptions = ruleOptions[1]
let printableConfig = rulePrimaryOptions ? JSON.stringify(rulePrimaryOptions) : ""
if (printableConfig && ruleSecondaryOptions) {
printableConfig += ", " + JSON.stringify(ruleSecondaryOptions)
}
function createCaseDescription(code) {
let text = `\n> rule: ${ruleName}\n`
text += `> config: ${printableConfig}\n`
text += `> code: ${JSON.stringify(code)}\n`
return text
}
// Process the code through the rule and return
// the PostCSS LazyResult promise
function postcssProcess(code) {
const postcssProcessOptions = {}
switch (schema.syntax) {
case "scss":
postcssProcessOptions.syntax = scssSyntax
break
case "less":
postcssProcessOptions.syntax = lessSyntax
break
case "sugarss":
postcssProcessOptions.syntax = sugarss
break
}
const processor = postcss()
processor.use(assignDisabledRanges)
if (schema.preceedingPlugins) {
schema.preceedingPlugins.forEach(plugin => processor.use(plugin))
}
return processor.use(rule(rulePrimaryOptions, ruleSecondaryOptions)).process(code, postcssProcessOptions)
}
// Apply the basic positive checks unless
// explicitly told not to
const passingTestCases = schema.skipBasicChecks ? schema.accept : basicChecks.concat(schema.accept)
if (passingTestCases && passingTestCases.length) {
passingTestCases.forEach(acceptedCase => {
if (!acceptedCase) {
return
}
const assertionDescription = spaceJoin(acceptedCase.description, "should be accepted")
const resultPromise = postcssProcess(acceptedCase.code).then(postcssResult => {
const warnings = postcssResult.warnings()
return [{
expected: 0,
actual: warnings.length,
description: assertionDescription,
}]
}).catch(err => console.log(err.stack)) // eslint-disable-line no-console
equalityCheck(resultPromise, {
comparisonCount: 1,
caseDescription: createCaseDescription(acceptedCase.code),
completeAssertionDescription: assertionDescription,
})
})
}
if (schema.reject && schema.reject.length) {
schema.reject.forEach(rejectedCase => {
let completeAssertionDescription = "should register one warning"
let comparisonCount = 1
if (rejectedCase.line) {
comparisonCount++
completeAssertionDescription += ` on line ${rejectedCase.line}`
}
if (rejectedCase.column !== undefined) {
comparisonCount++
completeAssertionDescription += ` on column ${rejectedCase.column}`
}
if (rejectedCase.message) {
comparisonCount++
completeAssertionDescription += ` with message "${rejectedCase.message}"`
}
const resultPromise = postcssProcess(rejectedCase.code).then(postcssResult => {
const warnings = postcssResult.warnings()
const warning = warnings[0]
const comparisons = [{
expected: 1,
actual: warnings.length,
description: spaceJoin(rejectedCase.description, "should register one warning"),
}]
if (rejectedCase.line) {
comparisons.push({
expected: rejectedCase.line,
actual: _.get(warning, "line"),
description: spaceJoin(rejectedCase.description, `should warn on line ${rejectedCase.line}`),
})
}
if (rejectedCase.column !== undefined) {
comparisons.push({
expected: rejectedCase.column,
actual: _.get(warning, "column"),
description: spaceJoin(rejectedCase.description, `should warn on column ${rejectedCase.column}`),
})
}
if (rejectedCase.message) {
comparisons.push({
expected: rejectedCase.message,
actual: _.get(warning, "text"),
description: spaceJoin(rejectedCase.description, `should warn with message ${rejectedCase.message}`),
})
}
return comparisons
}).catch(err => console.log(err.stack)) // eslint-disable-line no-console
equalityCheck(resultPromise, {
comparisonCount,
completeAssertionDescription,
caseDescription: createCaseDescription(rejectedCase.code),
only: rejectedCase.only,
})
})
}
}
function spaceJoin() {
return _.compact(Array.from(arguments)).join(" ")
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 1 1 1 | "use strict"
const _ = require("lodash")
module.exports = function () {
const mergeWithArgs = [{}]
Array.from(arguments).forEach((arg) => mergeWithArgs.push(arg))
mergeWithArgs.push(mergeCustomizer)
return _.mergeWith.apply(_, mergeWithArgs)
}
function mergeCustomizer(objValue, srcValue) {
if (_.isArray(objValue, mergeCustomizer)) {
return objValue.concat(srcValue)
}
}
|
| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| FileCache.js | 44.44% | (12 / 27) | 0% | (0 / 12) | 0% | (0 / 5) | 44.44% | (12 / 27) | |
| atRuleParamIndex.js | 20% | (1 / 5) | 0% | (0 / 2) | 0% | (0 / 1) | 20% | (1 / 5) | |
| beforeBlockString.js | 4.55% | (1 / 22) | 0% | (0 / 22) | 0% | (0 / 1) | 4.55% | (1 / 22) | |
| blockString.js | 57.14% | (4 / 7) | 0% | (0 / 2) | 0% | (0 / 1) | 57.14% | (4 / 7) | |
| blurComments.js | 33.33% | (1 / 3) | 0% | (0 / 4) | 0% | (0 / 1) | 33.33% | (1 / 3) | |
| blurFunctionArguments.js | 16.67% | (3 / 18) | 0% | (0 / 6) | 0% | (0 / 1) | 16.67% | (3 / 18) | |
| blurInterpolation.js | 33.33% | (1 / 3) | 0% | (0 / 4) | 0% | (0 / 1) | 33.33% | (1 / 3) | |
| checkAgainstRule.js | 18.18% | (4 / 22) | 0% | (0 / 14) | 0% | (0 / 1) | 26.67% | (4 / 15) | |
| configurationError.js | 100% | (4 / 4) | 100% | (0 / 0) | 100% | (1 / 1) | 100% | (4 / 4) | |
| containsString.js | 12.5% | (2 / 16) | 0% | (0 / 12) | 0% | (0 / 2) | 13.33% | (2 / 15) | |
| declarationValueIndex.js | 25% | (1 / 4) | 100% | (0 / 0) | 0% | (0 / 1) | 25% | (1 / 4) | |
| findAnimationName.js | 22.22% | (6 / 27) | 0% | (0 / 18) | 0% | (0 / 1) | 22.22% | (6 / 27) | |
| findAtRuleContext.js | 14.29% | (1 / 7) | 0% | (0 / 4) | 0% | (0 / 1) | 14.29% | (1 / 7) | |
| findFontFamily.js | 18.75% | (9 / 48) | 0% | (0 / 38) | 0% | (0 / 2) | 18.75% | (9 / 48) | |
| findListStyleType.js | 21.74% | (5 / 23) | 0% | (0 / 16) | 0% | (0 / 1) | 21.74% | (5 / 23) | |
| functionArgumentsSearch.js | 37.5% | (3 / 8) | 0% | (0 / 2) | 0% | (0 / 1) | 37.5% | (3 / 8) | |
| getCacheFile.js | 31.25% | (5 / 16) | 0% | (0 / 5) | 0% | (0 / 2) | 31.25% | (5 / 16) | |
| getIsFileIgnored.js | 50% | (4 / 8) | 0% | (0 / 4) | 0% | (0 / 1) | 50% | (4 / 8) | |
| getModulePath.js | 33.33% | (3 / 9) | 0% | (0 / 4) | 0% | (0 / 1) | 33.33% | (3 / 9) | |
| getUnitFromValueNode.js | 35.71% | (5 / 14) | 0% | (0 / 13) | 0% | (0 / 1) | 35.71% | (5 / 14) | |
| hasBlock.js | 50% | (1 / 2) | 100% | (0 / 0) | 0% | (0 / 1) | 50% | (1 / 2) | |
| hasEmptyBlock.js | 50% | (1 / 2) | 0% | (0 / 2) | 0% | (0 / 1) | 50% | (1 / 2) | |
| hasEmptyLine.js | 25% | (1 / 4) | 0% | (0 / 6) | 0% | (0 / 1) | 33.33% | (1 / 3) | |
| hasInterpolation.js | 57.14% | (4 / 7) | 0% | (0 / 5) | 0% | (0 / 1) | 57.14% | (4 / 7) | |
| hasLessInterpolation.js | 25% | (1 / 4) | 0% | (0 / 2) | 0% | (0 / 1) | 25% | (1 / 4) | |
| hasPsvInterpolation.js | 25% | (1 / 4) | 0% | (0 / 2) | 0% | (0 / 1) | 25% | (1 / 4) | |
| hasScssInterpolation.js | 25% | (1 / 4) | 0% | (0 / 2) | 0% | (0 / 1) | 25% | (1 / 4) | |
| hash.js | 66.67% | (2 / 3) | 100% | (0 / 0) | 0% | (0 / 1) | 66.67% | (2 / 3) | |
| isAutoprefixable.js | 38.46% | (5 / 13) | 0% | (0 / 4) | 0% | (0 / 5) | 38.46% | (5 / 13) | |
| isCounterIncrementCustomIdentValue.js | 42.86% | (3 / 7) | 0% | (0 / 4) | 0% | (0 / 1) | 42.86% | (3 / 7) | |
| isCounterResetCustomIdentValue.js | 42.86% | (3 / 7) | 0% | (0 / 4) | 0% | (0 / 1) | 42.86% | (3 / 7) | |
| isCustomMediaQuery.js | 50% | (1 / 2) | 100% | (0 / 0) | 0% | (0 / 1) | 50% | (1 / 2) | |
| isCustomProperty.js | 50% | (1 / 2) | 100% | (0 / 0) | 0% | (0 / 1) | 50% | (1 / 2) | |
| isCustomPropertySet.js | 60% | (3 / 5) | 0% | (0 / 4) | 0% | (0 / 1) | 60% | (3 / 5) | |
| isCustomSelector.js | 50% | (1 / 2) | 100% | (0 / 0) | 0% | (0 / 1) | 50% | (1 / 2) | |
| isKeyframeRule.js | 33.33% | (1 / 3) | 0% | (0 / 2) | 0% | (0 / 1) | 33.33% | (1 / 3) | |
| isKeyframeSelector.js | 28.57% | (2 / 7) | 0% | (0 / 4) | 0% | (0 / 1) | 28.57% | (2 / 7) | |
| isNumbery.js | 50% | (1 / 2) | 0% | (0 / 2) | 0% | (0 / 1) | 50% | (1 / 2) | |
| isOnlyWhitespace.js | 25% | (2 / 8) | 0% | (0 / 2) | 0% | (0 / 1) | 25% | (2 / 8) | |
| isRangeContextMediaFeature.js | 50% | (1 / 2) | 0% | (0 / 3) | 0% | (0 / 1) | 50% | (1 / 2) | |
| isSingleLineString.js | 50% | (1 / 2) | 100% | (0 / 0) | 0% | (0 / 1) | 50% | (1 / 2) | |
| isStandardSyntaxAtRule.js | 16.67% | (1 / 6) | 0% | (0 / 9) | 0% | (0 / 1) | 16.67% | (1 / 6) | |
| isStandardSyntaxDeclaration.js | 9.09% | (1 / 11) | 0% | (0 / 13) | 0% | (0 / 1) | 9.09% | (1 / 11) | |
| isStandardSyntaxFunction.js | 25% | (1 / 4) | 0% | (0 / 2) | 0% | (0 / 1) | 25% | (1 / 4) | |
| isStandardSyntaxMediaFeature.js | 25% | (2 / 8) | 0% | (0 / 4) | 0% | (0 / 1) | 25% | (2 / 8) | |
| isStandardSyntaxMediaFeatureName.js | 25% | (1 / 4) | 0% | (0 / 2) | 0% | (0 / 1) | 25% | (1 / 4) | |
| isStandardSyntaxProperty.js | 22.22% | (2 / 9) | 0% | (0 / 6) | 0% | (0 / 1) | 22.22% | (2 / 9) | |
| isStandardSyntaxRule.js | 17.65% | (3 / 17) | 0% | (0 / 18) | 0% | (0 / 1) | 17.65% | (3 / 17) | |
| isStandardSyntaxSelector.js | 28.57% | (2 / 7) | 0% | (0 / 4) | 0% | (0 / 1) | 28.57% | (2 / 7) | |
| isStandardSyntaxTypeSelector.js | 15.38% | (2 / 13) | 0% | (0 / 13) | 0% | (0 / 1) | 15.38% | (2 / 13) | |
| isStandardSyntaxUrl.js | 23.53% | (4 / 17) | 0% | (0 / 23) | 0% | (0 / 1) | 23.53% | (4 / 17) | |
| isStandardSyntaxValue.js | 22.22% | (2 / 9) | 0% | (0 / 6) | 0% | (0 / 1) | 22.22% | (2 / 9) | |
| isValidFontSize.js | 18.75% | (3 / 16) | 0% | (0 / 10) | 0% | (0 / 1) | 18.75% | (3 / 16) | |
| isValidHex.js | 50% | (1 / 2) | 100% | (0 / 0) | 0% | (0 / 1) | 50% | (1 / 2) | |
| isVariable.js | 50% | (1 / 2) | 100% | (0 / 0) | 0% | (0 / 1) | 50% | (1 / 2) | |
| isWhitespace.js | 50% | (1 / 2) | 100% | (0 / 0) | 0% | (0 / 1) | 50% | (1 / 2) | |
| matchesStringOrRegExp.js | 13.64% | (3 / 22) | 0% | (0 / 16) | 0% | (0 / 3) | 13.64% | (3 / 22) | |
| nextNonCommentNode.js | 16.67% | (1 / 6) | 0% | (0 / 6) | 0% | (0 / 1) | 20% | (1 / 5) | |
| nodeContextLookup.js | 16.67% | (2 / 12) | 0% | (0 / 2) | 0% | (0 / 3) | 16.67% | (2 / 12) | |
| optionsMatches.js | 66.67% | (2 / 3) | 0% | (0 / 4) | 0% | (0 / 1) | 66.67% | (2 / 3) | |
| parseSelector.js | 40% | (2 / 5) | 100% | (0 / 0) | 0% | (0 / 1) | 40% | (2 / 5) | |
| rawNodeString.js | 16.67% | (1 / 6) | 0% | (0 / 2) | 0% | (0 / 1) | 16.67% | (1 / 6) | |
| report.js | 6.67% | (2 / 30) | 0% | (0 / 31) | 0% | (0 / 1) | 6.67% | (2 / 30) | |
| ruleMessages.js | 87.5% | (7 / 8) | 100% | (2 / 2) | 50% | (1 / 2) | 87.5% | (7 / 8) | |
| validateObjectWithStringArrayProps.js | 22.22% | (2 / 9) | 0% | (0 / 4) | 0% | (0 / 1) | 25% | (2 / 8) | |
| validateOptions.js | 9.84% | (6 / 61) | 0% | (0 / 41) | 0% | (0 / 4) | 10% | (6 / 60) | |
| whitespaceChecker.js | 10.37% | (14 / 135) | 0% | (0 / 136) | 0% | (0 / 12) | 10.37% | (14 / 135) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 1 1 1 1 1 1 1 1 1 1 1 1 | /* @flow */
"use strict"
const fileEntryCache = require("file-entry-cache")
const path = require("path")
const debug = require("debug")("stylelint:file-cache")
const getCacheFile = require("./getCacheFile")
const DEFAULT_CACHE_LOCATION = "./.stylelintcache"
const DEFAULT_HASH = ""
function FileCache(cacheLocation/*: ?string */, hashOfConfig/*: ?string */) {
const cacheFile = path.resolve(getCacheFile(cacheLocation || DEFAULT_CACHE_LOCATION, process.cwd()))
debug(`Cache file is created at ${cacheFile}`)
this._fileCache = fileEntryCache.create(cacheFile)
this._hashOfConfig = hashOfConfig || DEFAULT_HASH
}
FileCache.prototype.hasFileChanged = function (absoluteFilepath) {
// Get file descriptor compares current metadata against cached
// one and stores the result to "changed" prop.w
const descriptor = this._fileCache.getFileDescriptor(absoluteFilepath)
const meta = descriptor.meta || {}
const changed = descriptor.changed || meta.hashOfConfig !== this._hashOfConfig
if (!changed) {
debug(`Skip linting ${absoluteFilepath}. File hasn't changed.`)
}
// Mutate file descriptor object and store config hash to each file.
// Running lint with different config should invalidate the cache.
if (meta.hashOfConfig !== this._hashOfConfig) {
meta.hashOfConfig = this._hashOfConfig
}
return changed
}
FileCache.prototype.reconcile = function () {
this._fileCache.reconcile()
}
FileCache.prototype.destroy = function () {
this._fileCache.destroy()
}
FileCache.prototype.removeEntry = function (absoluteFilepath) {
this._fileCache.removeEntry(absoluteFilepath)
}
module.exports = FileCache
|
| 1 2 3 4 5 6 7 8 9 10 11 12 | 1 | /* @flow */ "use strict" module.exports = function (atRule/*: postcss$atRule*/)/*: number*/ { // Initial 1 is for the `@` let index = 1 + atRule.name.length if (atRule.raws.afterName) { index += atRule.raws.afterName.length } return index } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 1 | /* @flow */ "use strict" module.exports = function ( statement/*: Object*/, options/*:: ?: Object*/ )/*: string*/ { options = options || {} let result = "" let rule/*: postcss$rule*/ let atRule/*: postcss$atRule*/ if (statement.type === "rule") { rule = statement } if (statement.type === "atrule") { atRule = statement } if (!rule && !atRule) { return result } const before = (statement.raws.before || "") if (!options.noRawBefore) { result += before } if (rule) { result += rule.selector } if (atRule) { result += "@" + atRule.name + (atRule.raws.afterName || "") + atRule.params } const between = statement.raws.between if (between !== undefined) { result += between } return result } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 1 1 1 1 | /* @flow */
"use strict"
const beforeBlockString = require("./beforeBlockString")
const hasBlock = require("./hasBlock")
const rawNodeString = require("./rawNodeString")
/**
* Return a CSS statement's block -- the string that starts and `{` and ends with `}`.
*
* If the statement has no block (e.g. `@import url(foo.css);`),
* return undefined.
*
* @param {Rule|AtRule} statement - postcss rule or at-rule node
* @return {string|undefined}
*/
module.exports = function (statement/*: postcss$rule | postcss$atRule*/)/*: string | boolean*/ {
if (!hasBlock(statement)) {
return false
}
return rawNodeString(statement).slice(beforeBlockString(statement).length)
}
|
| 1 2 3 4 5 6 7 8 9 | 1 | /* @flow */ "use strict" module.exports = function (source/*: string*/)/*: string*/ { const blurChar/*: string*/ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "`" return source.replace(/\/\*.*\*\//g, blurChar) } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 1 1 1 | /* @flow */
"use strict"
const _ = require("lodash")
const balancedMatch = require("balanced-match")
/**
* Replace all of the characters that are arguments to a certain
* CSS function with some innocuous character.
*
* This is useful if you need to use a RegExp to find a string
* but want to ignore matches in certain functions (e.g. `url()`,
* which might contain all kinds of false positives).
*
* For example:
* blurFunctionArguments("abc url(abc) abc", "url") === "abc url(```) abc"
*
* @param {string} source
* @param {string} functionName
* @param {[string]} blurChar="`"
* @return {string} - The result string, with the function arguments "blurred"
*/
module.exports = function (source/*: string*/, functionName/*: string*/)/*: string*/ {
const blurChar/*: string*/ = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "`"
const nameWithParen = `${functionName.toLowerCase()}(`
const lowerCaseSource = source.toLowerCase()
if (!_.includes(lowerCaseSource, nameWithParen)) {
return source
}
const functionNameLength/*: number*/ = functionName.length
let result = source
let searchStartIndex = 0
while (lowerCaseSource.indexOf(nameWithParen, searchStartIndex) !== -1) {
const openingParenIndex = lowerCaseSource.indexOf(nameWithParen, searchStartIndex) + functionNameLength
const closingParenIndex = balancedMatch("(", ")", lowerCaseSource.slice(openingParenIndex)).end + openingParenIndex
const argumentsLength = closingParenIndex - openingParenIndex - 1
result = result.slice(0, openingParenIndex + 1) + _.repeat(blurChar, argumentsLength) + result.slice(closingParenIndex)
searchStartIndex = closingParenIndex
}
return result
}
|
| 1 2 3 4 5 6 7 8 9 | 1 | /* @flow */ "use strict" module.exports = function (source/*: string*/)/*: string*/ { const blurChar/*: string*/ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : " " return source.replace(/[#@{}]+/g, blurChar) } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 1 1 1 1 | /* @flow */
"use strict"
const Result = require("postcss/lib/result")
const normalizeRuleSettings = require("../normalizeRuleSettings")
const rules = require("../rules")
// Useful for third-party code (e.g. plugins) to run a PostCSS Root
// against a specific rule and do something with the warnings
module.exports = function (
options/*: {
ruleName: string,
ruleSettings: stylelint$configRuleSettings,
root: Object,
}*/,
callback/*: Function*/
) {
if (!options) throw new Error("checkAgainstRule requires an options object with 'ruleName', 'ruleSettings', and 'root' properties")
if (!callback) throw new Error("checkAgainstRule requires a callback")
if (!options.ruleName) throw new Error("checkAgainstRule requires a 'ruleName' option")
if (!rules[options.ruleName]) throw new Error(`Rule '${options.ruleName}' does not exist`)
if (!options.ruleSettings) throw new Error("checkAgainstRule requires a 'ruleSettings' option")
if (!options.root) throw new Error("checkAgainstRule requires a 'root' option")
const settings = normalizeRuleSettings(options.ruleSettings, options.ruleName)
if (!settings) { return }
const tmpPostcssResult = new Result()
rules[options.ruleName](settings[0], settings[1])(options.root, tmpPostcssResult)
tmpPostcssResult.warnings().forEach(callback)
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | 1 1 1 1 | /* @flow */
"use strict"
/**
* Create configurationError from text and set CLI exit code
*/
module.exports = function (text/*: string */)/* Object */ {
const err/*: Object*/ = new Error(text)
err.code = 78
return err
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 1 1 | /* @flow */ "use strict" /** * Checks if a string contains a value. The comparison value can be a string or * an array of strings. * * Any strings starting and ending with `/` are ignored. Use the * matchesStringOrRegExp() util to match regexes. */ module.exports = function containsString( input/*: string*/, comparison/*: string | Array<string>*/ )/*: false | { match: string, pattern: string }*/ { if (!Array.isArray(comparison)) { return testAgainstString(input, comparison) } for (const comparisonItem of comparison) { const testResult = testAgainstString(input, comparisonItem) if (testResult) { return testResult } } return false } function testAgainstString(value, comparison) { if (!comparison) return false if (comparison[0] === "/" && comparison[comparison.length - 1] === "/") { return false } if (value.indexOf(comparison) >= 0) { return { match: value, pattern: comparison } } return false } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | 1 | /* @flow */ "use strict" /** * Get the index of a declaration's value */ module.exports = function (decl/*: Object*/)/*: number*/ { const beforeColon = decl.toString().indexOf(":") const afterColon = decl.raw("between").length - decl.raw("between").indexOf(":") return beforeColon + afterColon } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | 1 1 1 1 1 1 | /* @flow */
"use strict"
const keywordSets = require("../reference/keywordSets")
const getUnitFromValueNode = require("./getUnitFromValueNode")
const isStandardSyntaxValue = require("./isStandardSyntaxValue")
const isVariable = require("./isVariable")
const postcssValueParser = require("postcss-value-parser")
/**
* Get the font-families within a `font` shorthand property value.
*/
module.exports = function findAnimationName(value/*: string*/)/*: Array<Object>*/ {
const animationNames = []
const valueNodes = postcssValueParser(value)
// Handle `inherit`, `initial` and etc
if (valueNodes.nodes.length === 1 && keywordSets.basicKeywords.has(valueNodes.nodes[0].value.toLowerCase())) {
return [valueNodes.nodes[0]]
}
valueNodes.walk(valueNode => {
if (valueNode.type === "function") {
return false
}
if (valueNode.type !== "word") {
return
}
const valueLowerCase = valueNode.value.toLowerCase()
// Ignore non standard syntax
if (!isStandardSyntaxValue(valueLowerCase)) {
return
}
// Ignore variables
if (isVariable(valueLowerCase)) {
return
}
// Ignore keywords for other font parts
if (keywordSets.animationShorthandKeywords.has(valueLowerCase)) {
return
}
// Ignore numbers with units
const unit = getUnitFromValueNode(valueNode)
if (unit || unit === "") {
return
}
animationNames.push(valueNode)
})
return animationNames
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 1 | /* @flow */ "use strict" /** * Find the at-rule in which a rule is nested. * * Returns `null` if the rule is not nested within an at-rule. */ module.exports = function findAtRuleContext( rule/*: postcss$rule */ )/*: ?postcss$atRule*/ { const parent = rule.parent if (parent.type === "root") { return null } if (parent.type === "atrule") { return parent } return findAtRuleContext(parent) } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | 1 1 1 1 1 1 1 1 1 | /* @flow */
"use strict"
const keywordSets = require("../reference/keywordSets")
const isNumbery = require("./isNumbery")
const isStandardSyntaxValue = require("./isStandardSyntaxValue")
const isValidFontSize = require("./isValidFontSize")
const isVariable = require("./isVariable")
const postcssValueParser = require("postcss-value-parser")
const nodeTypesToCheck = new Set([ "word", "string", "space", "div" ])
function joinValueNodes(firstNode, secondNode, charactersBetween) {
firstNode.value = firstNode.value + charactersBetween + secondNode.value
return firstNode
}
/**
* Get the font-families within a `font` shorthand property value.
*
* @param {string} value
* @return {object} Collection font-family nodes
*/
module.exports = function findFontFamily(value/*: string*/)/*: Array<Object>*/ {
const fontFamilies = []
const valueNodes = postcssValueParser(value)
// Handle `inherit`, `initial` and etc
if (valueNodes.nodes.length === 1 && keywordSets.basicKeywords.has(valueNodes.nodes[0].value.toLowerCase())) {
return [valueNodes.nodes[0]]
}
let needMergeNodesByValue = false
let mergeCharacters = null
valueNodes.walk((valueNode, index, nodes) => {
if (valueNode.type === "function") {
return false
}
if (!nodeTypesToCheck.has(valueNode.type)) {
return
}
const valueLowerCase = valueNode.value.toLowerCase()
// Ignore non standard syntax
if (!isStandardSyntaxValue(valueLowerCase)) {
return
}
// Ignore variables
if (isVariable(valueLowerCase)) {
return
}
// Ignore keywords for other font parts
if (keywordSets.fontShorthandKeywords.has(valueLowerCase) && !keywordSets.fontFamilyKeywords.has(valueLowerCase)) {
return
}
// Ignore font-sizes
if (isValidFontSize(valueNode.value)) {
return
}
// Ignore anything come after a <font-size>/, because it's a line-height
if (nodes[index - 1] && nodes[index - 1].value === "/" && nodes[index - 2] && isValidFontSize(nodes[index - 2].value)) {
return
}
// Ignore number values
if (isNumbery(valueLowerCase)) {
return
}
// Detect when a space or comma is dividing a list of font-families, and save the joining character.
if ((valueNode.type === "space" || valueNode.type === "div" && valueNode.value !== ",") && fontFamilies.length !== 0) {
needMergeNodesByValue = true
mergeCharacters = valueNode.value
return
} else if (valueNode.type === "space" || valueNode.type === "div") {
return
}
const fontFamily = valueNode
if (needMergeNodesByValue) {
joinValueNodes(fontFamilies[fontFamilies.length - 1], valueNode, mergeCharacters)
needMergeNodesByValue = false
mergeCharacters = null
} else {
fontFamilies.push(fontFamily)
}
})
return fontFamilies
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 1 1 1 1 1 | /* @flow */
"use strict"
const isStandardSyntaxValue = require("./isStandardSyntaxValue")
const isVariable = require("./isVariable")
const keywordSets = require("../reference/keywordSets")
const postcssValueParser = require("postcss-value-parser")
/**
* Get the list-style-type within a `list-style` shorthand property value.
*/
module.exports = function findListStyleType(value/*: string*/)/*: Array<Object>*/ {
const listStyleTypes = []
const valueNodes = postcssValueParser(value)
// Handle `inherit`, `initial` and etc
if (valueNodes.nodes.length === 1 && keywordSets.listStyleTypeKeywords.has(valueNodes.nodes[0].value.toLowerCase())) {
return [valueNodes.nodes[0]]
}
valueNodes.walk(valueNode => {
if (valueNode.type === "function") {
return false
}
if (valueNode.type !== "word") {
return
}
const valueLowerCase = valueNode.value.toLowerCase()
// Ignore non standard syntax
if (!isStandardSyntaxValue(valueLowerCase)) {
return
}
// Ignore variables
if (isVariable(valueLowerCase)) {
return
}
// Ignore keywords for other font parts
if (keywordSets.listStylePositionKeywords.has(valueLowerCase) || keywordSets.listStyleImageKeywords.has(valueLowerCase)) {
return
}
listStyleTypes.push(valueNode)
})
return listStyleTypes
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 1 1 1 | /* @flow */
"use strict"
const balancedMatch = require("balanced-match")
const styleSearch = require("style-search")
/**
* Search a CSS string for functions by name.
* For every match, invoke the callback, passing the function's
* "argument(s) string" (whatever is inside the parentheses)
* as an argument.
*
* Callback will be called once for every matching function found,
* with the function's "argument(s) string" and its starting index
* as the arguments.
*/
module.exports = function (
source/*: string*/,
functionName/*: string*/,
callback/*: Function*/
) {
styleSearch({
source,
target: functionName,
functionNames: "check",
}, match => {
if (source[match.endIndex] !== "(") {
return
}
const parensMatch = balancedMatch("(", ")", source.substr(match.startIndex))
callback(parensMatch.body, match.endIndex + 1)
})
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 1 1 1 1 1 | "use strict"
const hash = require("./hash")
const path = require("path")
const fs = require("fs")
/**
* Return the cacheFile to be used by stylelint, based on whether the provided parameter is
* a directory or looks like a directory (ends in `path.sep`), in which case the file
* name will be `cacheFile/.cache_hashOfCWD`.
*
* If cacheFile points to a file or looks like a file, then it will just use that file.
*
* @param {string} cacheFile - The name of file to be used to store the cache
* @param {string} cwd - Current working directory. Used for tests
* @returns {string} Resolved path to the cache file
*/
module.exports = function getCacheFile(cacheFile, cwd) {
/*
* Make sure path separators are normalized for environment/os.
* Also, keep trailing path separator if present.
*/
cacheFile = path.normalize(cacheFile)
const resolvedCacheFile = path.resolve(cwd, cacheFile)
// If the last character passed is a path separator, we assume is a directory.
const looksLikeADirectory = cacheFile[cacheFile.length - 1] === path.sep
/**
* Return the default cache file name when provided parameter is a directory.
* @returns {string} - Resolved path to the cacheFile
*/
function getCacheFileForDirectory() {
return path.join(resolvedCacheFile, `.stylelintcache_${hash(cwd)}`)
}
let fileStats
try {
fileStats = fs.lstatSync(resolvedCacheFile)
} catch (ex) {
fileStats = null
}
if (looksLikeADirectory || (fileStats && fileStats.isDirectory())) {
// Return path to provided directory with generated file name.
return getCacheFileForDirectory()
}
// Return normalized path to cache file.
return resolvedCacheFile
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 1 1 1 1 | "use strict"
const ignore = require("ignore")
const micromatch = require("micromatch")
const path = require("path")
module.exports = function getIsFileIgnored(
ignorePatterns/*: Array<string>*/,
ignoreFiles/*: string | Array<string>*/
)/*: Function */ {
const ignorePatternsFilter = ignore().add(ignorePatterns).createFilter()
return file => {
const filepathRelativeToCwd = path.relative(process.cwd(), file)
return ignorePatternsFilter && !ignorePatternsFilter(filepathRelativeToCwd) || ignoreFiles && micromatch(file, ignoreFiles).length
}
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 1 1 1 | /* @flow */
"use strict"
const configurationError = require("./configurationError")
const resolveFrom = require("resolve-from")
module.exports = function (basedir/*: string*/, lookup/*: string*/)/*: string*/ {
// First try to resolve from the provided directory,
// then try to resolve from process.cwd.
let path = resolveFrom(basedir, lookup)
if (!path) {
path = resolveFrom(process.cwd(), lookup)
}
if (!path) {
throw configurationError(`Could not find "${lookup}". Do you need a \`configBasedir\`?`)
}
return path
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 1 1 1 1 1 | /* @flow */
"use strict"
const blurInterpolation = require("./blurInterpolation")
const _ = require("lodash")
const isStandardSyntaxValue = require("./isStandardSyntaxValue")
const valueParser = require("postcss-value-parser")
/**
* Get unit from value node
*
* Returns `null` if the unit is not found.
*/
module.exports = function (node/*: Object*/)/*: ?string*/ {
if (!node || node && !node.value) {
return null
}
const value = blurInterpolation(node.value, "")
// ignore hack unit
.replace("\\0", "").replace("\\9", "")
// ignore decimal place
.replace(".", "")
if (node.type !== "word" || !isStandardSyntaxValue(value) || !_.isFinite(parseInt(value)) || node.value[0] === "#") {
return null
}
const parsedUnit = valueParser.unit(value)
if (!parsedUnit) {
return null
}
return parsedUnit.unit
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 1 | /* @flow */
"use strict"
/**
* Check if a statement has an block (empty or otherwise).
*
* @param {Rule|AtRule} statement - postcss rule or at-rule node
* @return {boolean} True if `statement` has a block (empty or otherwise)
*/
module.exports = function (
statement/*: postcss$rule | postcss$atRule*/
)/*: boolean*/ {
return statement.nodes !== undefined
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 1 | /* @flow */
"use strict"
/**
* Check if a statement has an empty block.
*
* @param {Rule|AtRule} statement - postcss rule or at-rule node
* @return {boolean} True if the statement has a block and it is empty
*/
module.exports = function (
statement/*: postcss$rule | postcss$atRule*/
)/*: boolean*/ {
return statement.nodes !== undefined // has block
&& statement.nodes.length === 0 // and is empty
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 | 1 | /* @flow */ "use strict" /** * Check if a string contains at least one empty line */ module.exports = function (string/*:: ?: string*/)/*: boolean*/ { if (string === "" || string === undefined) return false return string.indexOf("\n\n") !== -1 || string.indexOf("\n\r\n") !== -1 } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 1 1 1 1 | /* @flow */
"use strict"
const hasLessInterpolation = require("../utils/hasLessInterpolation")
const hasPsvInterpolation = require("../utils/hasPsvInterpolation")
const hasScssInterpolation = require("../utils/hasScssInterpolation")
/**
* Check whether a string has interpolation
*
* @param {string} string
* @return {boolean} If `true`, a string has interpolation
*/
module.exports = function (string/*: string*/)/*: boolean*/ {
// SCSS or Less interpolation
if (hasLessInterpolation(string) || hasScssInterpolation(string) || hasPsvInterpolation(string)) {
return true
}
return false
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 1 | /* @flow */
"use strict"
/**
* Check whether a string has less interpolation
*
* @param {string} string
* @return {boolean} If `true`, a string has less interpolation
*/
module.exports = function (string/*: string*/)/*: boolean*/ {
if (/@{.+?}/.test(string)) {
return true
}
return false
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 1 | /* @flow */ "use strict" /** * Check whether a string has postcss-simple-vars interpolation */ module.exports = function (string/*: string*/)/*: boolean*/ { if (/\$\(.+?\)/.test(string)) { return true } return false } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 1 | /* @flow */ "use strict" /** * Check whether a string has scss interpolation */ module.exports = function (string/*: string*/)/*: boolean*/ { if (/#{.+?}/.test(string)) { return true } return false } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | 1 1 | "use strict"
const murmur = require("imurmurhash")
/**
* hash the given string
* @param {string} str the string to hash
* @returns {string} the hash
*/
module.exports = function hash(str) {
return murmur(str).result().toString(36)
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | 1 1 1 1 1 | /* @flow */
"use strict"
const Browsers = require("autoprefixer/lib/browsers")
const Prefixes = require("autoprefixer/lib/prefixes")
const autoprefixer = require("autoprefixer")
/**
* Use Autoprefixer's secret powers to determine whether or
* not a certain CSS identifier contains a vendor prefix that
* Autoprefixer, given the standardized identifier, could add itself.
*
* Used by `*-no-vendor-prefix-*` rules to find superfluous
* vendor prefixes.
*/
const prefixes = new Prefixes(autoprefixer.data.prefixes, new Browsers(autoprefixer.data.browsers, []))
/**
* Most identifier types have to be looked up in a unique way,
* so we're exposing special functions for each.
*/
module.exports = {
atRuleName(identifier/*: string*/)/*: boolean*/ {
return prefixes.remove[`@${identifier.toLowerCase()}`]
},
selector(identifier/*: string*/)/*: boolean*/ {
return prefixes.remove.selectors.some(selectorObj => {
return identifier.toLowerCase() === selectorObj.prefixed
})
},
mediaFeatureName(identifier/*: string*/)/*: boolean*/ {
return identifier.toLowerCase().indexOf("device-pixel-ratio") !== -1
},
property(identifier/*: string*/)/*: boolean*/ {
return autoprefixer.data.prefixes[prefixes.unprefixed(identifier.toLowerCase())]
},
propertyValue(prop/*: string*/, value/*: string*/)/*: boolean*/ {
const possiblePrefixableValues = prefixes.remove[prop.toLowerCase()] && prefixes.remove[prop.toLowerCase()].values
return possiblePrefixableValues && possiblePrefixableValues.some(valueObj => {
return value.toLowerCase() === valueObj.prefixed
})
},
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 1 1 1 | /* @flow */
"use strict"
const keywordSets = require("../reference/keywordSets")
const _ = require("lodash")
/**
* Check value is a custom ident
*/
module.exports = function (value/*: string*/)/*: boolean*/ {
const valueLowerCase = value.toLowerCase()
if (keywordSets.counterIncrementKeywords.has(valueLowerCase) || _.isFinite(parseInt(valueLowerCase))) {
return false
}
return true
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 1 1 1 | /* @flow */
"use strict"
const keywordSets = require("../reference/keywordSets")
const _ = require("lodash")
/**
* Check value is a custom ident
*/
module.exports = function (value/*: string*/)/*: boolean*/ {
const valueLowerCase = value.toLowerCase()
if (keywordSets.counterResetKeywords.has(valueLowerCase) || _.isFinite(parseInt(valueLowerCase))) {
return false
}
return true
}
|
| 1 2 3 4 5 6 7 8 9 10 11 | 1 | /* @flow */ "use strict" /** * Check whether a media query is a custom */ module.exports = function (mediaQuery/*: string*/)/*: boolean*/ { return mediaQuery.slice(0, 2) === "--" } |
| 1 2 3 4 5 6 7 8 9 10 11 | 1 | /* @flow */ "use strict" /** * Check whether a property is a custom one */ module.exports = function (property/*: string*/)/*: boolean*/ { return property.slice(0, 2) === "--" } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 1 1 1 | /* @flow */
"use strict"
const _ = require("lodash")
const hasBlock = require("../utils/hasBlock")
/**
* Check whether a Node is a custom property set
*/
module.exports = function (node/*: Object*/)/*: boolean*/ {
const selector = _.get(node, "raws.selector.raw", node.selector)
return node.type === "rule" && hasBlock(node) && selector.slice(0, 2) === "--" && selector.slice(-1) === ":"
}
|
| 1 2 3 4 5 6 7 8 9 10 11 | 1 | /* @flow */ "use strict" /** * Check whether a selector is a custom one */ module.exports = function (selector/*: string*/)/*: boolean*/ { return (selector.slice(0, 3) === ":--") } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | 1 | /* @flow */ "use strict" /** * Check if a rule is a keyframe one */ module.exports = function (rule/*: postcss$rule*/)/*: boolean*/ { const parent = rule.parent return parent.type === "atrule" && parent.name.toLowerCase() === "keyframes" } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 1 1 | /* @flow */
"use strict"
const keywordSets = require("../reference/keywordSets")
/**
* Check whether a string is a keyframe selector.
*/
module.exports = function (selector/*: string*/)/*: boolean*/ {
if (keywordSets.keyframeSelectorKeywords.has(selector)) {
return true
}
// Percentages
if (/^(?:\d+\.?\d*|\d*\.?\d+)%$/.test(selector)) {
return true
}
return false
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 | 1 | // Too weird for Flow "use strict" /** * Check whether it's a number or a number-like string: * i.e. when coerced to a number it == itself. */ module.exports = function (value) { return value.trim().length !== 0 && Number(value) == value } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 1 1 | /* @flow */
"use strict"
const isWhitespace = require("./isWhitespace")
/**
* Returns a Boolean indicating whether the the input string is only whitespace.
*/
module.exports = function (input/*: string*/)/*: boolean*/ {
let isOnlyWhitespace = true
for (let i = 0, l = input.length; i < l; i++) {
if (!isWhitespace(input[i])) {
isOnlyWhitespace = false
break
}
}
return isOnlyWhitespace
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 1 | /* @flow */
"use strict"
/**
* Check whether a media feature is a range context one
*
* @param {string} media feature
* @return {boolean} If `true`, media feature is a range context one
*/
module.exports = function (mediaFeature/*: string*/)/*: boolean*/ {
return mediaFeature.indexOf("=") !== -1 || mediaFeature.indexOf("<") !== -1 || mediaFeature.indexOf(">") !== -1
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 1 | /* @flow */
"use strict"
/**
* Check if a string is a single line (i.e. does not contain
* any newline characters).
*
* @param {string} input
* @return {boolean}
*/
module.exports = function (input/*: string*/)/*: boolean*/ {
return !/[\n\r]/.test(input)
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 1 | /* @flow */
"use strict"
/**
* Check whether a at-rule is standard
*
* @param {atRule} postcss at-rule node
* @return {boolean} If `true`, the declaration is standard
*/
module.exports = function (atRule/*: postcss$atRule*/)/*: boolean*/ {
// Ignore scss `@content` inside mixins
if (!atRule.nodes && atRule.params === "") {
return false
}
// Ignore detached ruleset `@detached-ruleset: { background: red; }; .top { @detached-ruleset(); }`
if (!atRule.nodes && atRule.raws.afterName === "" && atRule.params[0] === "(") {
return false
}
return true
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 1 | /* @flow */ "use strict" /** * Check whether a declaration is standard */ module.exports = function (decl/*: Object*/)/*: boolean*/ { const prop = decl.prop, parent = decl.parent // Declarations belong in a declaration block if (parent.type === "root") { return false } // SCSS var (e.g. $var: x), nested list (e.g. $list: (x)) or nested map (e.g. $map: (key:value)) if (prop[0] === "$") { return false } // Less var (e.g. @var: x), but exclude variable interpolation (e.g. @{var}) if (prop[0] === "@" && prop[1] !== "{") { return false } // SCSS nested properties (e.g. border: { style: solid; color: red; }) if (parent.selector && parent.selector[parent.selector.length - 1] === ":" && parent.selector.substring(0, 2) !== "--") { return false } return true } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 1 | /* @flow */ "use strict" /** * Check whether a function is standard */ module.exports = function (node/*: Object*/)/*: boolean*/ { // Function nodes without names are things in parentheses like Sass lists if (!node.value) { return false } return true } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 1 1 | /* @flow */
"use strict"
const hasInterpolation = require("../utils/hasInterpolation")
/**
* Check whether a media feature is standard
*/
module.exports = function (mediaFeature/*: string*/)/*: boolean*/ {
// Remove outside parens
mediaFeature = mediaFeature.slice(1, -1)
// Parentheticals used for non-standard operations e.g. ($var - 10)
if (mediaFeature.indexOf("(") !== -1) {
return false
}
// SCSS or Less interpolation
if (hasInterpolation(mediaFeature)) {
return false
}
return true
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 1 | /* @flow */ "use strict" /** * Check whether a media feature name is standard */ module.exports = function (mediaFeatureName/*: string*/)/*: boolean*/ { // SCSS interpolation if (/#{.+?}|\$.+?/.test(mediaFeatureName)) { return false } return true } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 1 1 | /* @flow */
"use strict"
const hasInterpolation = require("../utils/hasInterpolation")
/**
* Check whether a property is standard
*/
module.exports = function (property/*: string*/)/*: boolean*/ {
// SCSS var (e.g. $var: x), list (e.g. $list: (x)) or map (e.g. $map: (key:value))
if (property[0] === "$") {
return false
}
// Less var (e.g. @var: x)
if (property[0] === "@") {
return false
}
// SCSS or Less interpolation
if (hasInterpolation(property)) {
return false
}
return true
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 1 1 1 | /* @flow */
"use strict"
const _ = require("lodash")
const isCustomPropertySet = require("../utils/isCustomPropertySet")
/**
* Check whether a Node is a standard rule
*/
module.exports = function (rule/*: Object*/)/*: boolean*/ {
// Get full selector
const selector = _.get(rule, "raws.selector.raw", rule.selector)
// Custom property set (e.g. --custom-property-set: {})
if (isCustomPropertySet(rule)) {
return false
}
// Called Less mixin (e.g. a { .mixin() })
if (rule.ruleWithoutBody) {
return false
}
// Less detached rulesets
if (selector.slice(0, 1) === "@" && selector.slice(-1) === ":") {
return false
}
// Ignore mixin or &:extend rule
// https://github.com/webschik/postcss-less/blob/master/lib/less-parser.js#L52
if (rule.params && rule.params[0]) {
return false
}
// Non-outputting Less mixin definition (e.g. .mixin() {})
if (_.endsWith(selector, ")") && !_.includes(selector, ":")) {
return false
}
// Ignore Scss nested properties
if (selector.slice(-1) === ":") {
return false
}
return true
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 1 1 | /* @flow */
"use strict"
const hasInterpolation = require("../utils/hasInterpolation")
/**
* Check whether a selector is standard
*/
module.exports = function (selector/*: string*/)/*: boolean*/ {
// SCSS or Less interpolation
if (hasInterpolation(selector)) {
return false
}
// SCSS placeholder selectors
if (selector.indexOf("%") === 0) {
return false
}
return true
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 1 1 | /* @flow */
"use strict"
/**
* Check whether a type selector is standard
*
* @param {Node} postcss-selector-parser node (of type tag)
* @return {boolean} If `true`, the type selector is standard
*/
const keywordSets = require("../reference/keywordSets")
module.exports = function (node/*: Object*/)/*: boolean*/ {
// postcss-selector-parser includes the arguments to nth-child() functions
// as "tags", so we need to ignore them ourselves.
// The fake-tag's "parent" is actually a selector node, whose parent
// should be the :nth-child pseudo node.
const _node$parent$parent = node.parent.parent
const parentType = _node$parent$parent.type,
parentValue = _node$parent$parent.value
if (parentValue) {
const normalisedParentName = parentValue.toLowerCase().replace(/:+/, "")
if (parentType === "pseudo" && (keywordSets.aNPlusBNotationPseudoClasses.has(normalisedParentName) || keywordSets.linguisticPseudoClasses.has(normalisedParentName))) {
return false
}
}
// &-bar is a nesting selector combined with a suffix
if (node.prev() && node.prev().type === "nesting") {
return false
}
if (node.value[0] === "%") {
return false
}
return true
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 1 1 1 1 | /* @flow */
"use strict"
const hasLessInterpolation = require("../utils/hasLessInterpolation")
const hasPsvInterpolation = require("../utils/hasPsvInterpolation")
const hasScssInterpolation = require("../utils/hasScssInterpolation")
/**
* Check whether a URL is standard
*/
module.exports = function (url/*: string*/)/*: boolean*/ {
if (url.length === 0) {
return true
}
// Sass interpolation works anywhere
if (hasScssInterpolation(url) || hasPsvInterpolation(url)) {
return false
}
// Inside `'` and `"` work only LESS interpolation
if (url[0] === "'" && url[url.length - 1] === "'" || url[0] === "\"" && url[url.length - 1] === "\"") {
if (hasLessInterpolation(url)) {
return false
}
return true
}
// Less variable works only at the beginning
// Check is less variable, allow use '@url/some/path'
// https://github.com/less/less.js/blob/3.x/lib/less/parser/parser.js#L547
if (url[0] === "@" && /^@@?[\w-]+$/.test(url)) {
return false
}
// In url without quotes scss variable can be everywhere
// But in this case it is allowed to use only specific characters
// Also forbidden "/" at the end of url
if (url.indexOf("$") !== -1 && /^[\$\sA-Za-z0-9+-/*_'"\/]+$/.test(url) && url[url.length - 1] !== "/") {
return false
}
return true
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 1 1 | /* @flow */
"use strict"
const hasInterpolation = require("../utils/hasInterpolation")
/**
* Check whether a value is standard
*/
module.exports = function (value/*: string*/)/*: boolean*/ {
// SCSS variable
if (value[0] === "$") {
return false
}
// Less variable
if (value[0] === "@") {
return false
}
// SCSS or Less interpolation
if (hasInterpolation(value)) {
return false
}
return true
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 1 1 1 | /* @flow */
"use strict"
const keywordSets = require("../reference/keywordSets")
const valueParser = require("postcss-value-parser")
/**
* Check if a word is a font-size value.
*/
module.exports = function (word/*: string*/)/*: boolean*/ {
if (!word) {
return false
}
if (keywordSets.fontSizeKeywords.has(word)) {
return true
}
const numberUnit = valueParser.unit(word)
if (!numberUnit) {
return false
}
const unit = numberUnit.unit
if (unit === "%") {
return true
}
if (keywordSets.lengthUnits.has(unit.toLowerCase())) {
return true
}
return false
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 | 1 | /* @flow */ "use strict" /** * Check if a value is a valid 3, 4, 6 or 8 digit hex */ module.exports = function (value/*: string*/)/*: boolean*/ { return (/^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(value) ) } |
| 1 2 3 4 5 6 7 8 9 10 11 | 1 | /* @flow */ "use strict" /** * Check whether a word is a variable i.e var(--custom-property). */ module.exports = function (word/*: string*/)/*: boolean*/ { return word.toLowerCase().slice(0, 4) === "var(" } |
| 1 2 3 4 5 6 7 8 9 10 11 | 1 | /* @flow */ "use strict" /** * Check if a character is whitespace. */ module.exports = function (char/*: string*/)/*: boolean*/ { return [ " ", "\n", "\t", "\r", "\f" ].indexOf(char) !== -1 } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 1 1 1 | /* @flow */ "use strict" /** * Compares a string to a second value that, if it fits a certain convention, * is converted to a regular expression before the comparison. * If it doesn't fit the convention, then two strings are compared. * * Any strings starting and ending with `/` are interpreted * as regular expressions. */ module.exports = function matchesStringOrRegExp( input/*: string | Array<string>*/, comparison/*: string | Array<string>*/ )/*: false | { match: string, pattern: string}*/ { if (!Array.isArray(input)) { return testAgainstStringOrArray(input, comparison) } for (const inputItem of input) { const testResult = testAgainstStringOrArray(inputItem, comparison) if (testResult) { return testResult } } return false } function testAgainstStringOrArray(value, comparison) { if (!Array.isArray(comparison)) { return testAgainstString(value, comparison) } for (const comparisonItem of comparison) { const testResult = testAgainstString(value, comparisonItem) if (testResult) { return testResult } } return false } function testAgainstString(value, comparison) { const comparisonIsRegex = comparison[0] === "/" && comparison[comparison.length - 1] === "/" if (comparisonIsRegex) { const valueMatches = new RegExp(comparison.slice(1, -1)).test(value) return valueMatches ? { match: value, pattern: comparison } : false } return value === comparison ? { match: value, pattern: comparison } : false } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 1 | /* @flow */ "use strict" /** * Get the next non-comment node in a PostCSS AST * at or after a given node. */ module.exports = function nextNonCommentNode(startNode/*: Object*/)/*: ?Object*/ { if (!startNode || !startNode.next) return null if (startNode.type === "comment") { return nextNonCommentNode(startNode.next()) } return startNode } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 1 1 | // Too weird for Flow "use strict" /** * Create a collection of Maps that serve to contextualize a given node. * This is useful to ensure that you only compare nodes that share a certain * context. * * All nodes are initially contextualized by their input source. * From there, you can contextualize them however you want. * * For a usage example, see `selector-no-descending-specificity`. */ module.exports = function () { const contextMap = new Map() return { getContext(node) { const nodeSource = node.source.input.from const baseContext = creativeGetMap(contextMap, nodeSource) const subContexts = Array.from(arguments).slice(1) return subContexts.reduce((result, context) => { return creativeGetMap(result, context) }, baseContext) }, } } function creativeGetMap(someMap, someThing) { if (!someMap.has(someThing)) { someMap.set(someThing, new Map()) } return someMap.get(someThing) } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 1 1 | /* @flow */
"use strict"
const matchesStringOrRegExp = require("./matchesStringOrRegExp")
/**
* Check if an options object's propertyName contains a user-defined string or
* regex that matches the passed in input.
*/
module.exports = function optionsMatches(
options/*: Object*/,
propertyName/*: string*/,
input/*: string*/
)/*: boolean*/ {
return !!(options && options[propertyName] && typeof input === "string" && matchesStringOrRegExp(input.toLowerCase(), options[propertyName]))
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 1 1 | /* @flow */
"use strict"
const selectorParser = require("postcss-selector-parser")
module.exports = function (
selector/*: string*/,
result/*: Object*/,
node/*: Object*/,
cb/*: Function*/
) {
try {
selectorParser(cb).process(selector)
} catch (e) {
result.warn("Cannot parse selector", { node })
}
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 1 | /* @flow */ "use strict" /** * Stringify PostCSS node including its raw "before" string. */ module.exports = function (node/*: Object*/)/*: string*/ { let result = "" if (node.raws.before) { result += node.raws.before } result += node.toString() return result } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | 1 1 | /* @flow */
"use strict"
const _ = require("lodash")
/**
* Report a violation.
*
* This function accounts for `disabledRanges` attached to the result.
* That is, if the reported violation is within a disabledRange,
* it is ignored. Otherwise, it is attached to the result as a
* postcss warning.
*
* It also accounts for the rule's severity.
*
* You *must* pass *either* a node or a line number.
*/
module.exports = function (violation/*: {
ruleName: string,
result: Object,
message: string,
node: Object,
index?: number,
word?: string,
line?: number
}*/) {
const ruleName = violation.ruleName
const result = violation.result
const message = violation.message
const line = violation.line
const node = violation.node
const index = violation.index
const word = violation.word
result.stylelint = result.stylelint || {}
// In quiet mode, mere warnings are ignored
if (result.stylelint.quiet && result.stylelint.ruleSeverities[ruleName] !== "error") {
return
}
// If a line is not passed, use the node.positionBy method to get the
// line number that the complaint pertains to
const startLine = line || node.positionBy({ index }).line
if (result.stylelint.disabledRanges && !result.stylelint.ignoreDisables) {
const ranges = result.stylelint.disabledRanges[ruleName] || result.stylelint.disabledRanges.all
for (const range of ranges) {
if (
// If the violation is within a disabledRange,
// and that disabledRange's rules include this one,
// do not register a warning
range.start <= startLine && (range.end >= startLine || range.end === undefined) && (!range.rules || range.rules.indexOf(ruleName) !== -1)) {
return
}
}
}
const severity = _.get(result.stylelint, [ "ruleSeverities", ruleName ], "ignore")
if (!result.stylelint.stylelintError && severity === "error") {
result.stylelint.stylelintError = true
}
const warningProperties/*: Object*/ = {
severity,
rule: ruleName,
}
if (node) {
warningProperties.node = node
}
if (index) {
warningProperties.index = index
}
if (word) {
warningProperties.word = word
}
const warningMessage = _.get(result.stylelint, [ "customMessages", ruleName ], message)
result.warn(warningMessage, warningProperties)
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 1 175 316 316 87 229 316 | /* @flow */
"use strict"
/**
* Given an object of violation messages, return another
* that provides the same messages postfixed with the rule
* that has been violated.
*
* @param {string} ruleName
* @param {object} messages - Object whose keys are message identifiers
* and values are either message strings or functions that return message strings
* @return {object} New message object, whose messages will be marked with the rule name
*/
module.exports = function (
ruleName/*: string*/,
messages/*: Object*/
)/*: Object*/ {
return Object.keys(messages).reduce((newMessages, messageId) => {
const messageText = messages[messageId]
if (typeof messageText === "string") {
newMessages[messageId] = `${messageText} (${ruleName})`
} else {
newMessages[messageId] = function () {
return `${messageText.apply(null, arguments)} (${ruleName})`
}
}
return newMessages
}, {})
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 1 1 | /* @flow */
"use strict"
const _ = require("lodash")
/**
* Check whether the variable is an object and all it's properties are arrays of string values:
*
* ignoreProperties = {
* value1: ["item11", "item12", "item13"],
* value2: ["item21", "item22", "item23"],
* value3: ["item31", "item32", "item33"],
* }
*/
module.exports = function (value/*: Object*/)/*: boolean*/ {
if (!_.isPlainObject(value)) {
return false
}
return Object.keys(value).every(key => {
if (!_.isArray(value[key])) {
return false
}
// Make sure the array items are strings
return value[key].every(item => _.isString(item))
})
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | 1 1 1 1 1 1 | /* @flow */
"use strict"
const _ = require("lodash")
const ignoredOptions = [ "severity", "message" ]
/**
* Validate a rule's options.
*
* See existing rules for examples.
*
* @param {Result} result - postcss result
* @param {string} ruleName
* @param {...object} ...optionDescriptions - Each optionDescription can
* have the following properties:
* - `actual` (required): the actual passed option value or object.
* - `possible` (required): a schema representation of what values are
* valid for those options. `possible` should be an object if the
* options are an object, with corresponding keys; if the options are not an
* object, `possible` isn't, either. All `possible` value representations
* should be **arrays of either values or functions**. Values are === checked
* against `actual`. Functions are fed `actual` as an argument and their
* return value is interpreted: truthy = valid, falsy = invalid.
* - `optional` (optional): If this is `true`, `actual` can be undefined.
* @return {boolean} Whether or not the options are valid (true = valid)
*/
module.exports = function (
result/*: Object*/,
ruleName/*: string*/
)/*: boolean*/ {
let noErrors = true
const optionDescriptions = Array.from(arguments).slice(2)
optionDescriptions.forEach(optionDescription => {
validate(optionDescription, ruleName, complain)
})
function complain(message) {
noErrors = false
result.warn(message, {
stylelintType: "invalidOption",
})
_.set(result, "stylelint.stylelintError", true)
}
return noErrors
}
function validate(opts, ruleName, complain) {
const possible = opts.possible
const actual = opts.actual
const optional = opts.optional
if (actual === null || _.isEqual(actual, [null])) {
return
}
const nothingPossible = possible === undefined || Array.isArray(possible) && possible.length === 0
if (nothingPossible && actual === true) {
return
}
if (actual === undefined) {
if (nothingPossible || optional) {
return
}
complain(`Expected option value for rule "${ruleName}"`)
return
} else if (nothingPossible) {
complain(`Unexpected option value "${actual}" for rule "${ruleName}"`)
return
}
// If `possible` is a function ...
if (_.isFunction(possible)) {
if (!possible(actual)) {
complain(`Invalid option "${JSON.stringify(actual)}" for rule ${ruleName}`)
}
return
}
// If `possible` is an array instead of an object ...
if (!_.isPlainObject(possible)) {
[].concat(actual).forEach(a => {
if (isValid(possible, a)) {
return
}
complain(`Invalid option value "${a}" for rule "${ruleName}"`)
})
return
}
// If possible is an object ...
if (!_.isPlainObject(actual)) {
complain(`Invalid option value ${JSON.stringify(actual)} for rule "${ruleName}": ` + "should be an object")
return
}
Object.keys(actual).forEach(optionName => {
if (ignoredOptions.indexOf(optionName) !== -1) {
return
}
if (!possible[optionName]) {
complain(`Invalid option name "${optionName}" for rule "${ruleName}"`)
return
}
const actualOptionValue = actual[optionName];[].concat(actualOptionValue).forEach(a => {
if (isValid(possible[optionName], a)) {
return
}
complain(`Invalid value "${a}" for option "${optionName}" of rule "${ruleName}"`)
})
})
}
function isValid(possible, actual) {
const possibleList = [].concat(possible)
for (let i = 0, l = possibleList.length; i < l; i++) {
const possibility = possibleList[i]
if (typeof possibility === "function" && possibility(actual)) {
return true
}
if (actual === possibility) {
return true
}
}
}
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | "use strict"
const configurationError = require("./configurationError")
const isSingleLineString = require("./isSingleLineString")
const isWhitespace = require("./isWhitespace")
/**
* Create a whitespaceChecker, which exposes the following functions:
* - `before()`
* - `beforeAllowingIndentation()`
* - `after()`
* - `afterOneOnly()`
*
* @param {"space"|"newline"} targetWhitespace - This is a keyword instead
* of the actual character (e.g. " ") in order to accommodate
* different styles of newline ("\n" vs "\r\n")
* @param {
* "always"|"never"
* |"always-single-line"|"always-multi-line"
* | "never-single-line"|"never-multi-line"
* } expectation
* @param {object} messages - An object of message functions;
* calling `before*()` or `after*()` and the `expectation` that is passed
* determines which message functions are required
* @param {function} [messages.exectedBefore]
* @param {function} [messages.rejectedBefore]
* @param {function} [messages.expectedAfter]
* @param {function} [messages.rejectedAfter]
* @param {function} [messages.expectedBeforeSingleLine]
* @param {function} [messages.rejectedBeforeSingleLine]
* @param {function} [messages.expectedBeforeMultiLine]
* @param {function} [messages.rejectedBeforeMultiLine]
* @return {object} The checker, with its exposed checking functions
*/
module.exports = function (
targetWhitespace/*: "space" | "newline"*/,
expectation/*: "always" | "never" | "always-single-line"
| "always-multi-line" | "never-single-line"|"never-multi-line"*/,
messages/*: Object*/
)/*: {
before: Function,
beforeAllowingIndentation: Function,
after: Function,
afterOneOnly: Function
}*/ {
// Keep track of active arguments in order to avoid passing
// too much stuff around, making signatures long and confusing.
// This variable gets reset anytime a checking function is called.
let activeArgs
/**
* Check for whitespace *before* a character.
*
* @param {object} args - Named arguments object
* @param {string} args.source - The source string
* @param {number} args.index - The index of the character to check before
* @param {function} args.err - If a violation is found, this callback
* will be invoked with the relevant warning message.
* Typically this callback will report() the violation.
* @param {function} args.errTarget - If a violation is found, this string
* will be sent to the relevant warning message.
* @param {string} [args.lineCheckStr] - Single- and multi-line checkers
* will use this string to determine whether they should proceed,
* i.e. if this string is one line only, single-line checkers will check,
* multi-line checkers will ignore.
* If none is passed, they will use `source`.
* @param {boolean} [args.onlyOneChar=false] - Only check *one* character before.
* By default, "always-*" checks will look for the `targetWhitespace` one
* before and then ensure there is no whitespace two before. This option
* bypasses that second check.
* @param {boolean} [args.allowIndentation=false] - Allow arbitrary indentation
* between the `targetWhitespace` (almost definitely a newline) and the `index`.
* With this option, the checker will see if a newline *begins* the whitespace before
* the `index`.
*/
function before(args) {
const source = args.source
const index = args.index
const err = args.err
const errTarget = args.errTarget
const lineCheckStr = args.lineCheckStr
const onlyOneChar = args.onlyOneChar === undefined ? false : args.onlyOneChar
const allowIndentation = args.allowIndentation === undefined ? false : args.allowIndentation
activeArgs = { source, index, err, errTarget, onlyOneChar, allowIndentation }
switch (expectation) {
case "always":
expectBefore()
break
case "never":
rejectBefore()
break
case "always-single-line":
if (!isSingleLineString(lineCheckStr || source)) {
return
}
expectBefore(messages.expectedBeforeSingleLine)
break
case "never-single-line":
if (!isSingleLineString(lineCheckStr || source)) {
return
}
rejectBefore(messages.rejectedBeforeSingleLine)
break
case "always-multi-line":
if (isSingleLineString(lineCheckStr || source)) {
return
}
expectBefore(messages.expectedBeforeMultiLine)
break
case "never-multi-line":
if (isSingleLineString(lineCheckStr || source)) {
return
}
rejectBefore(messages.rejectedBeforeMultiLine)
break
default:
throw configurationError(`Unknown expectation "${expectation}"`)
}
}
/**
* Check for whitespace *after* a character.
*
* Parameters are pretty much the same as for `before()`, above, just substitute
* the word "after" for "before".
*/
function after(args) {
const source = args.source
const index = args.index
const err = args.err
const errTarget = args.errTarget
const lineCheckStr = args.lineCheckStr
const onlyOneChar = args.onlyOneChar === undefined ? false : args.onlyOneChar
activeArgs = { source, index, err, errTarget, onlyOneChar }
switch (expectation) {
case "always":
expectAfter()
break
case "never":
rejectAfter()
break
case "always-single-line":
if (!isSingleLineString(lineCheckStr || source)) {
return
}
expectAfter(messages.expectedAfterSingleLine)
break
case "never-single-line":
if (!isSingleLineString(lineCheckStr || source)) {
return
}
rejectAfter(messages.rejectedAfterSingleLine)
break
case "always-multi-line":
if (isSingleLineString(lineCheckStr || source)) {
return
}
expectAfter(messages.expectedAfterMultiLine)
break
case "never-multi-line":
if (isSingleLineString(lineCheckStr || source)) {
return
}
rejectAfter(messages.rejectedAfterMultiLine)
break
default:
throw configurationError(`Unknown expectation "${expectation}"`)
}
}
function beforeAllowingIndentation(obj) {
before(Object.assign({}, obj, { allowIndentation: true }))
}
function expectBefore() {
const messageFunc = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : messages.expectedBefore
if (activeArgs.allowIndentation) {
expectBeforeAllowingIndentation(messageFunc)
return
}
const _activeArgs = activeArgs
const source = _activeArgs.source,
index = _activeArgs.index
const oneCharBefore = source[index - 1]
const twoCharsBefore = source[index - 2]
if (!isValue(oneCharBefore)) {
return
}
if (targetWhitespace === "space" && oneCharBefore === " ") {
if (activeArgs.onlyOneChar || !isWhitespace(twoCharsBefore)) {
return
}
}
activeArgs.err(messageFunc(activeArgs.errTarget ? activeArgs.errTarget : source[index]))
}
function expectBeforeAllowingIndentation() {
const messageFunc = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : messages.expectedBefore
const _activeArgs2 = activeArgs
const source = _activeArgs2.source,
index = _activeArgs2.index,
err = _activeArgs2.err
const expectedChar = function () {
if (targetWhitespace === "newline") {
return "\n"
}
}()
let i = index - 1
while (source[i] !== expectedChar) {
if (source[i] === "\t" || source[i] === " ") {
i--
continue
}
err(messageFunc(activeArgs.errTarget ? activeArgs.errTarget : source[index]))
return
}
}
function rejectBefore() {
const messageFunc = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : messages.rejectedBefore
const _activeArgs3 = activeArgs
const source = _activeArgs3.source,
index = _activeArgs3.index
const oneCharBefore = source[index - 1]
if (isValue(oneCharBefore) && isWhitespace(oneCharBefore)) {
activeArgs.err(messageFunc(activeArgs.errTarget ? activeArgs.errTarget : source[index]))
}
}
function afterOneOnly(obj) {
after(Object.assign({}, obj, { onlyOneChar: true }))
}
function expectAfter() {
const messageFunc = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : messages.expectedAfter
const _activeArgs4 = activeArgs
const source = _activeArgs4.source,
index = _activeArgs4.index
const oneCharAfter = source[index + 1]
const twoCharsAfter = source[index + 2]
if (!isValue(oneCharAfter)) {
return
}
if (targetWhitespace === "newline") {
// If index is followed by a Windows CR-LF ...
if (oneCharAfter === "\r" && twoCharsAfter === "\n") {
if (activeArgs.onlyOneChar || !isWhitespace(source[index + 3])) {
return
}
}
// If index is followed by a Unix LF ...
if (oneCharAfter === "\n") {
if (activeArgs.onlyOneChar || !isWhitespace(twoCharsAfter)) {
return
}
}
}
if (targetWhitespace === "space" && oneCharAfter === " ") {
if (activeArgs.onlyOneChar || !isWhitespace(twoCharsAfter)) {
return
}
}
activeArgs.err(messageFunc(activeArgs.errTarget ? activeArgs.errTarget : source[index]))
}
function rejectAfter() {
const messageFunc = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : messages.rejectedAfter
const _activeArgs5 = activeArgs
const source = _activeArgs5.source,
index = _activeArgs5.index
const oneCharAfter = source[index + 1]
if (isValue(oneCharAfter) && isWhitespace(oneCharAfter)) {
activeArgs.err(messageFunc(activeArgs.errTarget ? activeArgs.errTarget : source[index]))
}
}
return {
before,
beforeAllowingIndentation,
after,
afterOneOnly,
}
}
function isValue(x) {
return x !== undefined && x !== null
}
|